blob: ad40c346a41e79d5095f1e53cca438842da803ca [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 Hellwig82ffb672005-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 Hellwig82ffb672005-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 Hellwig82ffb672005-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)
629 *
630 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800631 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 * protocol-specific driver must do this before it will be able to
633 * use any IOC resources, such as obtaining request frames.
634 *
635 * NOTES: The SCSI protocol driver currently calls this routine thrice
636 * in order to register separate callbacks; one for "normal" SCSI IO;
637 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
638 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530639 * Returns u8 valued "handle" in the range (and S.O.D. order)
640 * {N,...,7,6,5,...,1} if successful.
641 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
642 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530644u8
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530645mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass, char *func_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530647 u8 cb_idx;
648 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
650 /*
651 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
652 * (slot/handle 0 is reserved!)
653 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530654 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
655 if (MptCallbacks[cb_idx] == NULL) {
656 MptCallbacks[cb_idx] = cbfunc;
657 MptDriverClass[cb_idx] = dclass;
658 MptEvHandlers[cb_idx] = NULL;
659 last_drv_idx = cb_idx;
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530660 memcpy(MptCallbacksName[cb_idx], func_name,
661 strlen(func_name) > 50 ? 50 : strlen(func_name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 break;
663 }
664 }
665
666 return last_drv_idx;
667}
668
669/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
670/**
671 * mpt_deregister - Deregister a protocol drivers resources.
672 * @cb_idx: previously registered callback handle
673 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800674 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 * module is unloaded.
676 */
677void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530678mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600680 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 MptCallbacks[cb_idx] = NULL;
682 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
683 MptEvHandlers[cb_idx] = NULL;
684
685 last_drv_idx++;
686 }
687}
688
689/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
690/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800691 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 * @cb_idx: previously registered (via mpt_register) callback handle
693 * @ev_cbfunc: callback function
694 *
695 * This routine can be called by one or more protocol-specific drivers
696 * if/when they choose to be notified of MPT events.
697 *
698 * Returns 0 for success.
699 */
700int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530701mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600703 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 return -1;
705
706 MptEvHandlers[cb_idx] = ev_cbfunc;
707 return 0;
708}
709
710/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
711/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800712 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 * @cb_idx: previously registered callback handle
714 *
715 * Each protocol-specific driver should call this routine
716 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800717 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 */
719void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530720mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600722 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 return;
724
725 MptEvHandlers[cb_idx] = NULL;
726}
727
728/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
729/**
730 * mpt_reset_register - Register protocol-specific IOC reset handler.
731 * @cb_idx: previously registered (via mpt_register) callback handle
732 * @reset_func: reset function
733 *
734 * This routine can be called by one or more protocol-specific drivers
735 * if/when they choose to be notified of IOC resets.
736 *
737 * Returns 0 for success.
738 */
739int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530740mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530742 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 return -1;
744
745 MptResetHandlers[cb_idx] = reset_func;
746 return 0;
747}
748
749/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
750/**
751 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
752 * @cb_idx: previously registered callback handle
753 *
754 * Each protocol-specific driver should call this routine
755 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800756 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 */
758void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530759mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530761 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return;
763
764 MptResetHandlers[cb_idx] = NULL;
765}
766
767/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
768/**
769 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800770 * @dd_cbfunc: driver callbacks struct
771 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 */
773int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530774mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
776 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600777 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Eric Moore8d6d83e2007-09-14 18:47:40 -0600779 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400780 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
782 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
783
784 /* call per pci device probe entry point */
785 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600786 id = ioc->pcidev->driver ?
787 ioc->pcidev->driver->id_table : NULL;
788 if (dd_cbfunc->probe)
789 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 }
791
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400792 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793}
794
795/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
796/**
797 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800798 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 */
800void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530801mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802{
803 struct mpt_pci_driver *dd_cbfunc;
804 MPT_ADAPTER *ioc;
805
Eric Moore8d6d83e2007-09-14 18:47:40 -0600806 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 return;
808
809 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
810
811 list_for_each_entry(ioc, &ioc_list, list) {
812 if (dd_cbfunc->remove)
813 dd_cbfunc->remove(ioc->pcidev);
814 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200815
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 MptDeviceDriverHandlers[cb_idx] = NULL;
817}
818
819
820/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
821/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800822 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530823 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 * @ioc: Pointer to MPT adapter structure
825 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800826 * Obtain an MPT request frame from the pool (of 1024) that are
827 * allocated per MPT adapter.
828 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 * Returns pointer to a MPT request frame or %NULL if none are available
830 * or IOC is not active.
831 */
832MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530833mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834{
835 MPT_FRAME_HDR *mf;
836 unsigned long flags;
837 u16 req_idx; /* Request index */
838
839 /* validate handle and ioc identifier */
840
841#ifdef MFCNT
842 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600843 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
844 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845#endif
846
847 /* If interrupts are not attached, do not return a request frame */
848 if (!ioc->active)
849 return NULL;
850
851 spin_lock_irqsave(&ioc->FreeQlock, flags);
852 if (!list_empty(&ioc->FreeQ)) {
853 int req_offset;
854
855 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
856 u.frame.linkage.list);
857 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200858 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530859 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
861 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500862 req_idx = req_offset / ioc->req_sz;
863 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600865 /* Default, will be changed if necessary in SG generation */
866 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867#ifdef MFCNT
868 ioc->mfcnt++;
869#endif
870 }
871 else
872 mf = NULL;
873 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
874
875#ifdef MFCNT
876 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600877 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
878 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
879 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 mfcounter++;
881 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600882 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
883 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884#endif
885
Eric Moore29dd3602007-09-14 18:46:51 -0600886 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
887 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 return mf;
889}
890
891/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
892/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800893 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530894 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 * @ioc: Pointer to MPT adapter structure
896 * @mf: Pointer to MPT request frame
897 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800898 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 * specific MPT adapter.
900 */
901void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530902mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903{
904 u32 mf_dma_addr;
905 int req_offset;
906 u16 req_idx; /* Request index */
907
908 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530909 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
911 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500912 req_idx = req_offset / ioc->req_sz;
913 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
915
Prakash, Sathya436ace72007-07-24 15:42:08 +0530916 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200918 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600919 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
920 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
921 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
923}
924
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530925/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800926 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530927 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530928 * @ioc: Pointer to MPT adapter structure
929 * @mf: Pointer to MPT request frame
930 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800931 * Send a protocol-specific MPT request frame to an IOC using
932 * hi-priority request queue.
933 *
934 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530935 * specific MPT adapter.
936 **/
937void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530938mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530939{
940 u32 mf_dma_addr;
941 int req_offset;
942 u16 req_idx; /* Request index */
943
944 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530945 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530946 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
947 req_idx = req_offset / ioc->req_sz;
948 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
949 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
950
951 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
952
953 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
954 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
955 ioc->name, mf_dma_addr, req_idx));
956 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
957}
958
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
960/**
961 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 * @ioc: Pointer to MPT adapter structure
963 * @mf: Pointer to MPT request frame
964 *
965 * This routine places a MPT request frame back on the MPT adapter's
966 * FreeQ.
967 */
968void
969mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
970{
971 unsigned long flags;
972
973 /* Put Request back on FreeQ! */
974 spin_lock_irqsave(&ioc->FreeQlock, flags);
Kashyap, Desai2f187862009-05-29 16:52:37 +0530975 if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf)
976 goto out;
977 /* signature to know if this mf is freed */
978 mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
980#ifdef MFCNT
981 ioc->mfcnt--;
982#endif
Kashyap, Desai2f187862009-05-29 16:52:37 +0530983 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
985}
986
987/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
988/**
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530989 * mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 * @pAddr: virtual address for SGE
991 * @flagslength: SGE flags and data transfer length
992 * @dma_addr: Physical address
993 *
994 * This routine places a MPT request frame back on the MPT adapter's
995 * FreeQ.
996 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530997static void
998mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999{
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301000 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
1001 pSge->FlagsLength = cpu_to_le32(flagslength);
1002 pSge->Address = cpu_to_le32(dma_addr);
1003}
1004
1005/**
1006 * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
1007 * @pAddr: virtual address for SGE
1008 * @flagslength: SGE flags and data transfer length
1009 * @dma_addr: Physical address
1010 *
1011 * This routine places a MPT request frame back on the MPT adapter's
1012 * FreeQ.
1013 **/
1014static void
1015mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1016{
1017 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1018 pSge->Address.Low = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301019 (lower_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301020 pSge->Address.High = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301021 (upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301022 pSge->FlagsLength = cpu_to_le32
1023 ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1024}
1025
1026/**
Randy Dunlap9cf46a32009-06-13 19:37:18 -07001027 * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr (1078 workaround).
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301028 * @pAddr: virtual address for SGE
1029 * @flagslength: SGE flags and data transfer length
1030 * @dma_addr: Physical address
1031 *
1032 * This routine places a MPT request frame back on the MPT adapter's
1033 * FreeQ.
1034 **/
1035static void
1036mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1037{
1038 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1039 u32 tmp;
1040
1041 pSge->Address.Low = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301042 (lower_32_bits(dma_addr));
1043 tmp = (u32)(upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301044
1045 /*
1046 * 1078 errata workaround for the 36GB limitation
1047 */
1048 if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {
1049 flagslength |=
1050 MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
1051 tmp |= (1<<31);
1052 if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
1053 printk(KERN_DEBUG "1078 P0M2 addressing for "
1054 "addr = 0x%llx len = %d\n",
1055 (unsigned long long)dma_addr,
1056 MPI_SGE_LENGTH(flagslength));
1057 }
1058
1059 pSge->Address.High = cpu_to_le32(tmp);
1060 pSge->FlagsLength = cpu_to_le32(
1061 (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1062}
1063
1064/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1065/**
1066 * mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
1067 * @pAddr: virtual address for SGE
1068 * @next: nextChainOffset value (u32's)
1069 * @length: length of next SGL segment
1070 * @dma_addr: Physical address
1071 *
1072 */
1073static void
1074mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1075{
1076 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
1077 pChain->Length = cpu_to_le16(length);
1078 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
1079 pChain->NextChainOffset = next;
1080 pChain->Address = cpu_to_le32(dma_addr);
1081}
1082
1083/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1084/**
1085 * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
1086 * @pAddr: virtual address for SGE
1087 * @next: nextChainOffset value (u32's)
1088 * @length: length of next SGL segment
1089 * @dma_addr: Physical address
1090 *
1091 */
1092static void
1093mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1094{
1095 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 u32 tmp = dma_addr & 0xFFFFFFFF;
1097
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301098 pChain->Length = cpu_to_le16(length);
1099 pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
1100 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301102 pChain->NextChainOffset = next;
1103
1104 pChain->Address.Low = cpu_to_le32(tmp);
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301105 tmp = (u32)(upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301106 pChain->Address.High = cpu_to_le32(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107}
1108
1109/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1110/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001111 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301112 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 * @ioc: Pointer to MPT adapter structure
1114 * @reqBytes: Size of the request in bytes
1115 * @req: Pointer to MPT request frame
1116 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1117 *
1118 * This routine is used exclusively to send MptScsiTaskMgmt
1119 * requests since they are required to be sent via doorbell handshake.
1120 *
1121 * NOTE: It is the callers responsibility to byte-swap fields in the
1122 * request which are greater than 1 byte in size.
1123 *
1124 * Returns 0 for success, non-zero for failure.
1125 */
1126int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301127mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128{
Eric Moorecd2c6192007-01-29 09:47:47 -07001129 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 u8 *req_as_bytes;
1131 int ii;
1132
1133 /* State is known to be good upon entering
1134 * this function so issue the bus reset
1135 * request.
1136 */
1137
1138 /*
1139 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1140 * setting cb_idx/req_idx. But ONLY if this request
1141 * is in proper (pre-alloc'd) request buffer range...
1142 */
1143 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1144 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1145 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1146 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301147 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 }
1149
1150 /* Make sure there are no doorbells */
1151 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001152
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1154 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1155 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1156
1157 /* Wait for IOC doorbell int */
1158 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1159 return ii;
1160 }
1161
1162 /* Read doorbell and check for active bit */
1163 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1164 return -5;
1165
Eric Moore29dd3602007-09-14 18:46:51 -06001166 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001167 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
1169 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1170
1171 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1172 return -2;
1173 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001174
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 /* Send request via doorbell handshake */
1176 req_as_bytes = (u8 *) req;
1177 for (ii = 0; ii < reqBytes/4; ii++) {
1178 u32 word;
1179
1180 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1181 (req_as_bytes[(ii*4) + 1] << 8) |
1182 (req_as_bytes[(ii*4) + 2] << 16) |
1183 (req_as_bytes[(ii*4) + 3] << 24));
1184 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1185 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1186 r = -3;
1187 break;
1188 }
1189 }
1190
1191 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1192 r = 0;
1193 else
1194 r = -4;
1195
1196 /* Make sure there are no doorbells */
1197 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001198
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 return r;
1200}
1201
1202/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1203/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001204 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001205 * @ioc: Pointer to MPT adapter structure
1206 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001207 * @sleepFlag: Specifies whether the process can sleep
1208 *
1209 * Provides mechanism for the host driver to control the IOC's
1210 * Host Page Buffer access.
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001211 *
1212 * Access Control Value - bits[15:12]
1213 * 0h Reserved
1214 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1215 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1216 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1217 *
1218 * Returns 0 for success, non-zero for failure.
1219 */
1220
1221static int
1222mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1223{
1224 int r = 0;
1225
1226 /* return if in use */
1227 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1228 & MPI_DOORBELL_ACTIVE)
1229 return -1;
1230
1231 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1232
1233 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1234 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1235 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1236 (access_control_value<<12)));
1237
1238 /* Wait for IOC to clear Doorbell Status bit */
1239 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1240 return -2;
1241 }else
1242 return 0;
1243}
1244
1245/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1246/**
1247 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001248 * @ioc: Pointer to pointer to IOC adapter
1249 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001250 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001251 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001252 * Returns 0 for success, non-zero for failure.
1253 */
1254static int
1255mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1256{
1257 char *psge;
1258 int flags_length;
1259 u32 host_page_buffer_sz=0;
1260
1261 if(!ioc->HostPageBuffer) {
1262
1263 host_page_buffer_sz =
1264 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1265
1266 if(!host_page_buffer_sz)
1267 return 0; /* fw doesn't need any host buffers */
1268
1269 /* spin till we get enough memory */
1270 while(host_page_buffer_sz > 0) {
1271
1272 if((ioc->HostPageBuffer = pci_alloc_consistent(
1273 ioc->pcidev,
1274 host_page_buffer_sz,
1275 &ioc->HostPageBuffer_dma)) != NULL) {
1276
Prakash, Sathya436ace72007-07-24 15:42:08 +05301277 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001278 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001279 ioc->name, ioc->HostPageBuffer,
1280 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001281 host_page_buffer_sz));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001282 ioc->alloc_total += host_page_buffer_sz;
1283 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1284 break;
1285 }
1286
1287 host_page_buffer_sz -= (4*1024);
1288 }
1289 }
1290
1291 if(!ioc->HostPageBuffer) {
1292 printk(MYIOC_s_ERR_FMT
1293 "Failed to alloc memory for host_page_buffer!\n",
1294 ioc->name);
1295 return -999;
1296 }
1297
1298 psge = (char *)&ioc_init->HostPageBufferSGE;
1299 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1300 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001301 MPI_SGE_FLAGS_HOST_TO_IOC |
1302 MPI_SGE_FLAGS_END_OF_BUFFER;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001303 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1304 flags_length |= ioc->HostPageBuffer_sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301305 ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001306 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1307
1308return 0;
1309}
1310
1311/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1312/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001313 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 * @iocid: IOC unique identifier (integer)
1315 * @iocpp: Pointer to pointer to IOC adapter
1316 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001317 * Given a unique IOC identifier, set pointer to the associated MPT
1318 * adapter structure.
1319 *
1320 * Returns iocid and sets iocpp if iocid is found.
1321 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 */
1323int
1324mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1325{
1326 MPT_ADAPTER *ioc;
1327
1328 list_for_each_entry(ioc,&ioc_list,list) {
1329 if (ioc->id == iocid) {
1330 *iocpp =ioc;
1331 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001334
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 *iocpp = NULL;
1336 return -1;
1337}
1338
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301339/**
1340 * mpt_get_product_name - returns product string
1341 * @vendor: pci vendor id
1342 * @device: pci device id
1343 * @revision: pci revision id
1344 * @prod_name: string returned
1345 *
1346 * Returns product string displayed when driver loads,
1347 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1348 *
1349 **/
1350static void
1351mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1352{
1353 char *product_str = NULL;
1354
1355 if (vendor == PCI_VENDOR_ID_BROCADE) {
1356 switch (device)
1357 {
1358 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1359 switch (revision)
1360 {
1361 case 0x00:
1362 product_str = "BRE040 A0";
1363 break;
1364 case 0x01:
1365 product_str = "BRE040 A1";
1366 break;
1367 default:
1368 product_str = "BRE040";
1369 break;
1370 }
1371 break;
1372 }
1373 goto out;
1374 }
1375
1376 switch (device)
1377 {
1378 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1379 product_str = "LSIFC909 B1";
1380 break;
1381 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1382 product_str = "LSIFC919 B0";
1383 break;
1384 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1385 product_str = "LSIFC929 B0";
1386 break;
1387 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1388 if (revision < 0x80)
1389 product_str = "LSIFC919X A0";
1390 else
1391 product_str = "LSIFC919XL A1";
1392 break;
1393 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1394 if (revision < 0x80)
1395 product_str = "LSIFC929X A0";
1396 else
1397 product_str = "LSIFC929XL A1";
1398 break;
1399 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1400 product_str = "LSIFC939X A1";
1401 break;
1402 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1403 product_str = "LSIFC949X A1";
1404 break;
1405 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1406 switch (revision)
1407 {
1408 case 0x00:
1409 product_str = "LSIFC949E A0";
1410 break;
1411 case 0x01:
1412 product_str = "LSIFC949E A1";
1413 break;
1414 default:
1415 product_str = "LSIFC949E";
1416 break;
1417 }
1418 break;
1419 case MPI_MANUFACTPAGE_DEVID_53C1030:
1420 switch (revision)
1421 {
1422 case 0x00:
1423 product_str = "LSI53C1030 A0";
1424 break;
1425 case 0x01:
1426 product_str = "LSI53C1030 B0";
1427 break;
1428 case 0x03:
1429 product_str = "LSI53C1030 B1";
1430 break;
1431 case 0x07:
1432 product_str = "LSI53C1030 B2";
1433 break;
1434 case 0x08:
1435 product_str = "LSI53C1030 C0";
1436 break;
1437 case 0x80:
1438 product_str = "LSI53C1030T A0";
1439 break;
1440 case 0x83:
1441 product_str = "LSI53C1030T A2";
1442 break;
1443 case 0x87:
1444 product_str = "LSI53C1030T A3";
1445 break;
1446 case 0xc1:
1447 product_str = "LSI53C1020A A1";
1448 break;
1449 default:
1450 product_str = "LSI53C1030";
1451 break;
1452 }
1453 break;
1454 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1455 switch (revision)
1456 {
1457 case 0x03:
1458 product_str = "LSI53C1035 A2";
1459 break;
1460 case 0x04:
1461 product_str = "LSI53C1035 B0";
1462 break;
1463 default:
1464 product_str = "LSI53C1035";
1465 break;
1466 }
1467 break;
1468 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1469 switch (revision)
1470 {
1471 case 0x00:
1472 product_str = "LSISAS1064 A1";
1473 break;
1474 case 0x01:
1475 product_str = "LSISAS1064 A2";
1476 break;
1477 case 0x02:
1478 product_str = "LSISAS1064 A3";
1479 break;
1480 case 0x03:
1481 product_str = "LSISAS1064 A4";
1482 break;
1483 default:
1484 product_str = "LSISAS1064";
1485 break;
1486 }
1487 break;
1488 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1489 switch (revision)
1490 {
1491 case 0x00:
1492 product_str = "LSISAS1064E A0";
1493 break;
1494 case 0x01:
1495 product_str = "LSISAS1064E B0";
1496 break;
1497 case 0x02:
1498 product_str = "LSISAS1064E B1";
1499 break;
1500 case 0x04:
1501 product_str = "LSISAS1064E B2";
1502 break;
1503 case 0x08:
1504 product_str = "LSISAS1064E B3";
1505 break;
1506 default:
1507 product_str = "LSISAS1064E";
1508 break;
1509 }
1510 break;
1511 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1512 switch (revision)
1513 {
1514 case 0x00:
1515 product_str = "LSISAS1068 A0";
1516 break;
1517 case 0x01:
1518 product_str = "LSISAS1068 B0";
1519 break;
1520 case 0x02:
1521 product_str = "LSISAS1068 B1";
1522 break;
1523 default:
1524 product_str = "LSISAS1068";
1525 break;
1526 }
1527 break;
1528 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1529 switch (revision)
1530 {
1531 case 0x00:
1532 product_str = "LSISAS1068E A0";
1533 break;
1534 case 0x01:
1535 product_str = "LSISAS1068E B0";
1536 break;
1537 case 0x02:
1538 product_str = "LSISAS1068E B1";
1539 break;
1540 case 0x04:
1541 product_str = "LSISAS1068E B2";
1542 break;
1543 case 0x08:
1544 product_str = "LSISAS1068E B3";
1545 break;
1546 default:
1547 product_str = "LSISAS1068E";
1548 break;
1549 }
1550 break;
1551 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1552 switch (revision)
1553 {
1554 case 0x00:
1555 product_str = "LSISAS1078 A0";
1556 break;
1557 case 0x01:
1558 product_str = "LSISAS1078 B0";
1559 break;
1560 case 0x02:
1561 product_str = "LSISAS1078 C0";
1562 break;
1563 case 0x03:
1564 product_str = "LSISAS1078 C1";
1565 break;
1566 case 0x04:
1567 product_str = "LSISAS1078 C2";
1568 break;
1569 default:
1570 product_str = "LSISAS1078";
1571 break;
1572 }
1573 break;
1574 }
1575
1576 out:
1577 if (product_str)
1578 sprintf(prod_name, "%s", product_str);
1579}
1580
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301581/**
1582 * mpt_mapresources - map in memory mapped io
1583 * @ioc: Pointer to pointer to IOC adapter
1584 *
1585 **/
1586static int
1587mpt_mapresources(MPT_ADAPTER *ioc)
1588{
1589 u8 __iomem *mem;
1590 int ii;
Pravin Bathijae46b63b2009-12-02 17:51:46 -08001591 resource_size_t mem_phys;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301592 unsigned long port;
1593 u32 msize;
1594 u32 psize;
1595 u8 revision;
1596 int r = -ENODEV;
1597 struct pci_dev *pdev;
1598
1599 pdev = ioc->pcidev;
1600 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1601 if (pci_enable_device_mem(pdev)) {
1602 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1603 "failed\n", ioc->name);
1604 return r;
1605 }
1606 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1607 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1608 "MEM failed\n", ioc->name);
1609 return r;
1610 }
1611
1612 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1613
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301614 if (sizeof(dma_addr_t) > 4) {
1615 const uint64_t required_mask = dma_get_required_mask
1616 (&pdev->dev);
1617 if (required_mask > DMA_BIT_MASK(32)
1618 && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
1619 && !pci_set_consistent_dma_mask(pdev,
1620 DMA_BIT_MASK(64))) {
1621 ioc->dma_mask = DMA_BIT_MASK(64);
1622 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1623 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1624 ioc->name));
1625 } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1626 && !pci_set_consistent_dma_mask(pdev,
1627 DMA_BIT_MASK(32))) {
1628 ioc->dma_mask = DMA_BIT_MASK(32);
1629 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1630 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1631 ioc->name));
1632 } else {
1633 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1634 ioc->name, pci_name(pdev));
Tomas Henzl653c42d2010-07-26 16:41:13 +02001635 pci_release_selected_regions(pdev, ioc->bars);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301636 return r;
1637 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301638 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301639 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1640 && !pci_set_consistent_dma_mask(pdev,
1641 DMA_BIT_MASK(32))) {
1642 ioc->dma_mask = DMA_BIT_MASK(32);
1643 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1644 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1645 ioc->name));
1646 } else {
1647 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1648 ioc->name, pci_name(pdev));
Tomas Henzl653c42d2010-07-26 16:41:13 +02001649 pci_release_selected_regions(pdev, ioc->bars);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301650 return r;
1651 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301652 }
1653
1654 mem_phys = msize = 0;
1655 port = psize = 0;
1656 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1657 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1658 if (psize)
1659 continue;
1660 /* Get I/O space! */
1661 port = pci_resource_start(pdev, ii);
1662 psize = pci_resource_len(pdev, ii);
1663 } else {
1664 if (msize)
1665 continue;
1666 /* Get memmap */
1667 mem_phys = pci_resource_start(pdev, ii);
1668 msize = pci_resource_len(pdev, ii);
1669 }
1670 }
1671 ioc->mem_size = msize;
1672
1673 mem = NULL;
1674 /* Get logical ptr for PciMem0 space */
1675 /*mem = ioremap(mem_phys, msize);*/
1676 mem = ioremap(mem_phys, msize);
1677 if (mem == NULL) {
1678 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1679 " memory!\n", ioc->name);
Tomas Henzl653c42d2010-07-26 16:41:13 +02001680 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301681 return -EINVAL;
1682 }
1683 ioc->memmap = mem;
Pravin Bathijae46b63b2009-12-02 17:51:46 -08001684 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %llx\n",
1685 ioc->name, mem, (unsigned long long)mem_phys));
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301686
1687 ioc->mem_phys = mem_phys;
1688 ioc->chip = (SYSIF_REGS __iomem *)mem;
1689
1690 /* Save Port IO values in case we need to do downloadboot */
1691 ioc->pio_mem_phys = port;
1692 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1693
1694 return 0;
1695}
1696
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001698/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001699 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001701 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 *
1703 * This routine performs all the steps necessary to bring the IOC of
1704 * a MPT adapter to a OPERATIONAL state. This includes registering
1705 * memory regions, registering the interrupt, and allocating request
1706 * and reply memory pools.
1707 *
1708 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1709 * MPT adapter.
1710 *
1711 * Returns 0 for success, non-zero for failure.
1712 *
1713 * TODO: Add support for polled controllers
1714 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001715int
1716mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717{
1718 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301719 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 u8 revision;
1722 u8 pcixcmd;
1723 static int mpt_ids = 0;
1724#ifdef CONFIG_PROC_FS
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07001725 struct proc_dir_entry *dent;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726#endif
1727
Jesper Juhl56876192007-08-10 14:50:51 -07001728 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1729 if (ioc == NULL) {
1730 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1731 return -ENOMEM;
1732 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301733
Eric Moore29dd3602007-09-14 18:46:51 -06001734 ioc->id = mpt_ids++;
1735 sprintf(ioc->name, "ioc%d", ioc->id);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301736 dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Jesper Juhl56876192007-08-10 14:50:51 -07001737
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301738 /*
1739 * set initial debug level
1740 * (refer to mptdebug.h)
1741 *
1742 */
1743 ioc->debug_level = mpt_debug_level;
1744 if (mpt_debug_level)
1745 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301746
Eric Moore29dd3602007-09-14 18:46:51 -06001747 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001748
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301749 ioc->pcidev = pdev;
1750 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001751 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 return r;
1753 }
1754
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301755 /*
1756 * Setting up proper handlers for scatter gather handling
1757 */
1758 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
1759 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
1760 ioc->add_sge = &mpt_add_sge_64bit_1078;
1761 else
1762 ioc->add_sge = &mpt_add_sge_64bit;
1763 ioc->add_chain = &mpt_add_chain_64bit;
1764 ioc->sg_addr_size = 8;
1765 } else {
1766 ioc->add_sge = &mpt_add_sge;
1767 ioc->add_chain = &mpt_add_chain;
1768 ioc->sg_addr_size = 4;
1769 }
1770 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
1771
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 ioc->alloc_total = sizeof(MPT_ADAPTER);
1773 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1774 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001775
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301777 spin_lock_init(&ioc->taskmgmt_lock);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05301778 mutex_init(&ioc->internal_cmds.mutex);
1779 init_completion(&ioc->internal_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301780 mutex_init(&ioc->mptbase_cmds.mutex);
1781 init_completion(&ioc->mptbase_cmds.done);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301782 mutex_init(&ioc->taskmgmt_cmds.mutex);
1783 init_completion(&ioc->taskmgmt_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301784
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 /* Initialize the event logging.
1786 */
1787 ioc->eventTypes = 0; /* None */
1788 ioc->eventContext = 0;
1789 ioc->eventLogSize = 0;
1790 ioc->events = NULL;
1791
1792#ifdef MFCNT
1793 ioc->mfcnt = 0;
1794#endif
1795
Kashyap, Desai2f187862009-05-29 16:52:37 +05301796 ioc->sh = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 ioc->cached_fw = NULL;
1798
Uwe Kleine-König421f91d2010-06-11 12:17:00 +02001799 /* Initialize SCSI Config Data structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001801 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802
Michael Reed05e8ec12006-01-13 14:31:54 -06001803 /* Initialize the fc rport list head.
1804 */
1805 INIT_LIST_HEAD(&ioc->fc_rports);
1806
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 /* Find lookup slot. */
1808 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001809
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301810
1811 /* Initialize workqueue */
1812 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301813
Kashyap, Desai2f187862009-05-29 16:52:37 +05301814 snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN,
Kay Sieversaab0de22008-05-02 06:02:41 +02001815 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301816 ioc->reset_work_q =
1817 create_singlethread_workqueue(ioc->reset_work_q_name);
1818 if (!ioc->reset_work_q) {
1819 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1820 ioc->name);
1821 pci_release_selected_regions(pdev, ioc->bars);
1822 kfree(ioc);
1823 return -ENOMEM;
1824 }
1825
Eric Moore29dd3602007-09-14 18:46:51 -06001826 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1827 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301829 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1830 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1831
1832 switch (pdev->device)
1833 {
1834 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1835 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1836 ioc->errata_flag_1064 = 1;
1837 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1838 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1839 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1840 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301842 break;
1843
1844 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 /* 929X Chip Fix. Set Split transactions level
1847 * for PCIX. Set MOST bits to zero.
1848 */
1849 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1850 pcixcmd &= 0x8F;
1851 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1852 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 /* 929XL Chip Fix. Set MMRBC to 0x08.
1854 */
1855 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1856 pcixcmd |= 0x08;
1857 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301860 break;
1861
1862 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 /* 919X Chip Fix. Set Split transactions level
1864 * for PCIX. Set MOST bits to zero.
1865 */
1866 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1867 pcixcmd &= 0x8F;
1868 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001869 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301870 break;
1871
1872 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 /* 1030 Chip Fix. Disable Split transactions
1874 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1875 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 if (revision < C0_1030) {
1877 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1878 pcixcmd &= 0x8F;
1879 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1880 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301881
1882 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001883 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301884 break;
1885
1886 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1887 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001888 ioc->errata_flag_1064 = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301889 ioc->bus_type = SAS;
1890 break;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301891
1892 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1893 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1894 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001895 ioc->bus_type = SAS;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301896 break;
Eric Moore87cf8982006-06-27 16:09:26 -06001897 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301899
Kashyap, Desaie3829682009-01-08 14:27:16 +05301900 switch (ioc->bus_type) {
1901
1902 case SAS:
1903 ioc->msi_enable = mpt_msi_enable_sas;
1904 break;
1905
1906 case SPI:
1907 ioc->msi_enable = mpt_msi_enable_spi;
1908 break;
1909
1910 case FC:
1911 ioc->msi_enable = mpt_msi_enable_fc;
1912 break;
1913
1914 default:
1915 ioc->msi_enable = 0;
1916 break;
1917 }
Kashyap, Desai8ce13de2010-06-17 14:35:46 +05301918
1919 ioc->fw_events_off = 1;
1920
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001921 if (ioc->errata_flag_1064)
1922 pci_disable_io_access(pdev);
1923
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 spin_lock_init(&ioc->FreeQlock);
1925
1926 /* Disable all! */
1927 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1928 ioc->active = 0;
1929 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1930
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301931 /* Set IOC ptr in the pcidev's driver data. */
1932 pci_set_drvdata(ioc->pcidev, ioc);
1933
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 /* Set lookup ptr. */
1935 list_add_tail(&ioc->list, &ioc_list);
1936
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001937 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 */
1939 mpt_detect_bound_ports(ioc, pdev);
1940
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301941 INIT_LIST_HEAD(&ioc->fw_event_list);
1942 spin_lock_init(&ioc->fw_event_lock);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301943 snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301944 ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
1945
James Bottomleyc92f2222006-03-01 09:02:49 -06001946 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1947 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001948 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1949 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001950
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001952 if (ioc->alt_ioc)
1953 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301954 iounmap(ioc->memmap);
1955 if (r != -5)
1956 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301957
1958 destroy_workqueue(ioc->reset_work_q);
1959 ioc->reset_work_q = NULL;
1960
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 kfree(ioc);
1962 pci_set_drvdata(pdev, NULL);
1963 return r;
1964 }
1965
1966 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001967 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301968 if(MptDeviceDriverHandlers[cb_idx] &&
1969 MptDeviceDriverHandlers[cb_idx]->probe) {
1970 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 }
1972 }
1973
1974#ifdef CONFIG_PROC_FS
1975 /*
1976 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1977 */
1978 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1979 if (dent) {
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07001980 proc_create_data("info", S_IRUGO, dent, &mpt_iocinfo_proc_fops, ioc);
1981 proc_create_data("summary", S_IRUGO, dent, &mpt_summary_proc_fops, ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 }
1983#endif
1984
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301985 if (!ioc->alt_ioc)
1986 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1987 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1988
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 return 0;
1990}
1991
1992/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001993/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001994 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 */
1997
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001998void
1999mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000{
2001 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2002 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302003 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302004 unsigned long flags;
2005 struct workqueue_struct *wq;
2006
2007 /*
2008 * Stop polling ioc for fault condition
2009 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302010 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302011 wq = ioc->reset_work_q;
2012 ioc->reset_work_q = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302013 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302014 cancel_delayed_work(&ioc->fault_reset_work);
2015 destroy_workqueue(wq);
2016
Kashyap, Desai3eb08222009-05-29 16:47:26 +05302017 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2018 wq = ioc->fw_event_q;
2019 ioc->fw_event_q = NULL;
2020 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2021 destroy_workqueue(wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022
2023 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2024 remove_proc_entry(pname, NULL);
2025 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2026 remove_proc_entry(pname, NULL);
2027 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2028 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002029
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002031 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302032 if(MptDeviceDriverHandlers[cb_idx] &&
2033 MptDeviceDriverHandlers[cb_idx]->remove) {
2034 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 }
2036 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002037
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 /* Disable interrupts! */
2039 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2040
2041 ioc->active = 0;
2042 synchronize_irq(pdev->irq);
2043
2044 /* Clear any lingering interrupt */
2045 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2046
2047 CHIPREG_READ32(&ioc->chip->IntStatus);
2048
2049 mpt_adapter_dispose(ioc);
2050
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051}
2052
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053/**************************************************************************
2054 * Power Management
2055 */
2056#ifdef CONFIG_PM
2057/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002058/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002059 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002060 * @pdev: Pointer to pci_dev structure
2061 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002063int
2064mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065{
2066 u32 device_state;
2067 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302069 device_state = pci_choose_state(pdev, state);
2070 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2071 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2072 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073
2074 /* put ioc into READY_STATE */
2075 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2076 printk(MYIOC_s_ERR_FMT
2077 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2078 }
2079
2080 /* disable interrupts */
2081 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2082 ioc->active = 0;
2083
2084 /* Clear any lingering interrupt */
2085 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2086
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302087 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002088 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302089 pci_disable_msi(ioc->pcidev);
2090 ioc->pci_irq = -1;
2091 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302093 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 return 0;
2096}
2097
2098/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002099/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002100 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002101 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002103int
2104mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105{
2106 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2107 u32 device_state = pdev->current_state;
2108 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302109 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002110
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302111 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2112 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2113 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302115 pci_set_power_state(pdev, PCI_D0);
2116 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302118 ioc->pcidev = pdev;
2119 err = mpt_mapresources(ioc);
2120 if (err)
2121 return err;
2122
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302123 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2124 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2125 ioc->add_sge = &mpt_add_sge_64bit_1078;
2126 else
2127 ioc->add_sge = &mpt_add_sge_64bit;
2128 ioc->add_chain = &mpt_add_chain_64bit;
2129 ioc->sg_addr_size = 8;
2130 } else {
2131
2132 ioc->add_sge = &mpt_add_sge;
2133 ioc->add_chain = &mpt_add_chain;
2134 ioc->sg_addr_size = 4;
2135 }
2136 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2137
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302138 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2139 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2140 CHIPREG_READ32(&ioc->chip->Doorbell));
2141
2142 /*
2143 * Errata workaround for SAS pci express:
2144 * Upon returning to the D0 state, the contents of the doorbell will be
2145 * stale data, and this will incorrectly signal to the host driver that
2146 * the firmware is ready to process mpt commands. The workaround is
2147 * to issue a diagnostic reset.
2148 */
2149 if (ioc->bus_type == SAS && (pdev->device ==
2150 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2151 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2152 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2153 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2154 ioc->name);
2155 goto out;
2156 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302157 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158
2159 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302160 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2161 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2162 CAN_SLEEP);
2163 if (recovery_state != 0)
2164 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2165 "error:[%x]\n", ioc->name, recovery_state);
2166 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302168 "pci-resume: success\n", ioc->name);
2169 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302171
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172}
2173#endif
2174
James Bottomley4ff42a62006-05-17 18:06:52 -05002175static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302176mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002177{
2178 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2179 ioc->bus_type != SPI) ||
2180 (MptDriverClass[index] == MPTFC_DRIVER &&
2181 ioc->bus_type != FC) ||
2182 (MptDriverClass[index] == MPTSAS_DRIVER &&
2183 ioc->bus_type != SAS))
2184 /* make sure we only call the relevant reset handler
2185 * for the bus */
2186 return 0;
2187 return (MptResetHandlers[index])(ioc, reset_phase);
2188}
2189
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002191/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2193 * @ioc: Pointer to MPT adapter structure
2194 * @reason: Event word / reason
2195 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2196 *
2197 * This routine performs all the steps necessary to bring the IOC
2198 * to a OPERATIONAL state.
2199 *
2200 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2201 * MPT adapter.
2202 *
2203 * Returns:
2204 * 0 for success
2205 * -1 if failed to get board READY
2206 * -2 if READY but IOCFacts Failed
2207 * -3 if READY but PrimeIOCFifos Failed
2208 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302209 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302210 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 */
2212static int
2213mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2214{
2215 int hard_reset_done = 0;
2216 int alt_ioc_ready = 0;
2217 int hard;
2218 int rc=0;
2219 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 int ret = 0;
2221 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002222 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302223 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224
Eric Moore29dd3602007-09-14 18:46:51 -06002225 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2226 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227
2228 /* Disable reply interrupts (also blocks FreeQ) */
2229 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2230 ioc->active = 0;
2231
2232 if (ioc->alt_ioc) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302233 if (ioc->alt_ioc->active ||
2234 reason == MPT_HOSTEVENT_IOC_RECOVER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 reset_alt_ioc_active = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302236 /* Disable alt-IOC's reply interrupts
2237 * (and FreeQ) for a bit
2238 **/
2239 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2240 0xFFFFFFFF);
2241 ioc->alt_ioc->active = 0;
2242 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 }
2244
2245 hard = 1;
2246 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2247 hard = 0;
2248
2249 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2250 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002251 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2252 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253
2254 if (reset_alt_ioc_active && ioc->alt_ioc) {
2255 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002256 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2257 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002258 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 ioc->alt_ioc->active = 1;
2260 }
2261
2262 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302263 printk(MYIOC_s_WARN_FMT
2264 "NOT READY WARNING!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302266 ret = -1;
2267 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 }
2269
2270 /* hard_reset_done = 0 if a soft reset was performed
2271 * and 1 if a hard reset was performed.
2272 */
2273 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2274 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2275 alt_ioc_ready = 1;
2276 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05302277 printk(MYIOC_s_WARN_FMT
2278 ": alt-ioc Not ready WARNING!\n",
2279 ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 }
2281
2282 for (ii=0; ii<5; ii++) {
2283 /* Get IOC facts! Allow 5 retries */
2284 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2285 break;
2286 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002287
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288
2289 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002290 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2291 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 ret = -2;
2293 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2294 MptDisplayIocCapabilities(ioc);
2295 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002296
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 if (alt_ioc_ready) {
2298 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302299 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302300 "Initial Alt IocFacts failed rc=%x\n",
2301 ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 /* Retry - alt IOC was initialized once
2303 */
2304 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2305 }
2306 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302307 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002308 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 alt_ioc_ready = 0;
2310 reset_alt_ioc_active = 0;
2311 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2312 MptDisplayIocCapabilities(ioc->alt_ioc);
2313 }
2314 }
2315
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302316 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2317 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2318 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2319 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2320 IORESOURCE_IO);
2321 if (pci_enable_device(ioc->pcidev))
2322 return -5;
2323 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2324 "mpt"))
2325 return -5;
2326 }
2327
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002328 /*
2329 * Device is reset now. It must have de-asserted the interrupt line
2330 * (if it was asserted) and it should be safe to register for the
2331 * interrupt now.
2332 */
2333 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2334 ioc->pci_irq = -1;
2335 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302336 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002337 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002338 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302339 else
2340 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002341 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002342 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002343 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002344 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Kashyap, Desai2f187862009-05-29 16:52:37 +05302345 "interrupt %d!\n",
2346 ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302347 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002348 pci_disable_msi(ioc->pcidev);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302349 ret = -EBUSY;
2350 goto out;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002351 }
2352 irq_allocated = 1;
2353 ioc->pci_irq = ioc->pcidev->irq;
2354 pci_set_master(ioc->pcidev); /* ?? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302355 pci_set_drvdata(ioc->pcidev, ioc);
2356 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2357 "installed at interrupt %d\n", ioc->name,
2358 ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002359 }
2360 }
2361
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 /* Prime reply & request queues!
2363 * (mucho alloc's) Must be done prior to
2364 * init as upper addresses are needed for init.
2365 * If fails, continue with alt-ioc processing
2366 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302367 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
2368 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2370 ret = -3;
2371
2372 /* May need to check/upload firmware & data here!
2373 * If fails, continue with alt-ioc processing
2374 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302375 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
2376 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2378 ret = -4;
2379// NEW!
2380 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302381 printk(MYIOC_s_WARN_FMT
2382 ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002383 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 alt_ioc_ready = 0;
2385 reset_alt_ioc_active = 0;
2386 }
2387
2388 if (alt_ioc_ready) {
2389 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2390 alt_ioc_ready = 0;
2391 reset_alt_ioc_active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302392 printk(MYIOC_s_WARN_FMT
2393 ": alt-ioc: (%d) init failure WARNING!\n",
2394 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 }
2396 }
2397
2398 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2399 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302400 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002401 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402
2403 /* Controller is not operational, cannot do upload
2404 */
2405 if (ret == 0) {
2406 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002407 if (rc == 0) {
2408 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2409 /*
2410 * Maintain only one pointer to FW memory
2411 * so there will not be two attempt to
2412 * downloadboot onboard dual function
2413 * chips (mpt_adapter_disable,
2414 * mpt_diag_reset)
2415 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302416 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002417 "mpt_upload: alt_%s has cached_fw=%p \n",
2418 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302419 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002420 }
2421 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002422 printk(MYIOC_s_WARN_FMT
2423 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302424 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002425 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 }
2427 }
2428 }
2429
Kashyap, Desaifd761752009-05-29 16:39:06 +05302430 /* Enable MPT base driver management of EventNotification
2431 * and EventAck handling.
2432 */
2433 if ((ret == 0) && (!ioc->facts.EventState)) {
2434 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2435 "SendEventNotification\n",
2436 ioc->name));
2437 ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
2438 }
2439
2440 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2441 rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
2442
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 if (ret == 0) {
2444 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002445 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 ioc->active = 1;
2447 }
Kashyap, Desaifd761752009-05-29 16:39:06 +05302448 if (rc == 0) { /* alt ioc */
2449 if (reset_alt_ioc_active && ioc->alt_ioc) {
2450 /* (re)Enable alt-IOC! (reply interrupt) */
2451 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
2452 "reply irq re-enabled\n",
2453 ioc->alt_ioc->name));
2454 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2455 MPI_HIM_DIM);
2456 ioc->alt_ioc->active = 1;
2457 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 }
2459
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002461 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2463 * recursive scenario; GetLanConfigPages times out, timer expired
2464 * routine calls HardResetHandler, which calls into here again,
2465 * and we try GetLanConfigPages again...
2466 */
2467 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002468
2469 /*
Uwe Kleine-König421f91d2010-06-11 12:17:00 +02002470 * Initialize link list for inactive raid volumes.
Eric Mooreb506ade2007-01-29 09:45:37 -07002471 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002472 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002473 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2474
Kashyap, Desai2f187862009-05-29 16:52:37 +05302475 switch (ioc->bus_type) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002476
Kashyap, Desai2f187862009-05-29 16:52:37 +05302477 case SAS:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002478 /* clear persistency table */
2479 if(ioc->facts.IOCExceptions &
2480 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2481 ret = mptbase_sas_persist_operation(ioc,
2482 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2483 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002484 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002485 }
2486
2487 /* Find IM volumes
2488 */
2489 mpt_findImVolumes(ioc);
2490
Kashyap, Desai2f187862009-05-29 16:52:37 +05302491 /* Check, and possibly reset, the coalescing value
2492 */
2493 mpt_read_ioc_pg_1(ioc);
2494
2495 break;
2496
2497 case FC:
2498 if ((ioc->pfacts[0].ProtocolFlags &
2499 MPI_PORTFACTS_PROTOCOL_LAN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2501 /*
2502 * Pre-fetch the ports LAN MAC address!
2503 * (LANPage1_t stuff)
2504 */
2505 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302506 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2507 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302508 "LanAddr = %02X:%02X:%02X"
2509 ":%02X:%02X:%02X\n",
2510 ioc->name, a[5], a[4],
2511 a[3], a[2], a[1], a[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302513 break;
2514
2515 case SPI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 /* Get NVRAM and adapter maximums from SPP 0 and 2
2517 */
2518 mpt_GetScsiPortSettings(ioc, 0);
2519
2520 /* Get version and length of SDP 1
2521 */
2522 mpt_readScsiDevicePageHeaders(ioc, 0);
2523
2524 /* Find IM volumes
2525 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002526 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 mpt_findImVolumes(ioc);
2528
2529 /* Check, and possibly reset, the coalescing value
2530 */
2531 mpt_read_ioc_pg_1(ioc);
2532
2533 mpt_read_ioc_pg_4(ioc);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302534
2535 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 }
2537
2538 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302539 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 }
2541
Eric Moore0ccdb002006-07-11 17:33:13 -06002542 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002543 if ((ret != 0) && irq_allocated) {
2544 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302545 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002546 pci_disable_msi(ioc->pcidev);
2547 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 return ret;
2549}
2550
2551/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002552/**
2553 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 * @ioc: Pointer to MPT adapter structure
2555 * @pdev: Pointer to (struct pci_dev) structure
2556 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002557 * Search for PCI bus/dev_function which matches
2558 * PCI bus/dev_function (+/-1) for newly discovered 929,
2559 * 929X, 1030 or 1035.
2560 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2562 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2563 */
2564static void
2565mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2566{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002567 struct pci_dev *peer=NULL;
2568 unsigned int slot = PCI_SLOT(pdev->devfn);
2569 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 MPT_ADAPTER *ioc_srch;
2571
Prakash, Sathya436ace72007-07-24 15:42:08 +05302572 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002573 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002574 ioc->name, pci_name(pdev), pdev->bus->number,
2575 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002576
2577 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2578 if (!peer) {
2579 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2580 if (!peer)
2581 return;
2582 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583
2584 list_for_each_entry(ioc_srch, &ioc_list, list) {
2585 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002586 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 /* Paranoia checks */
2588 if (ioc->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302589 printk(MYIOC_s_WARN_FMT
2590 "Oops, already bound (%s <==> %s)!\n",
2591 ioc->name, ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 break;
2593 } else if (ioc_srch->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302594 printk(MYIOC_s_WARN_FMT
2595 "Oops, already bound (%s <==> %s)!\n",
2596 ioc_srch->name, ioc_srch->name,
2597 ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 break;
2599 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302600 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2601 "FOUND! binding %s <==> %s\n",
2602 ioc->name, ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 ioc_srch->alt_ioc = ioc;
2604 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 }
2606 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002607 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608}
2609
2610/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002611/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002613 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 */
2615static void
2616mpt_adapter_disable(MPT_ADAPTER *ioc)
2617{
2618 int sz;
2619 int ret;
2620
2621 if (ioc->cached_fw != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302622 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2623 "%s: Pushing FW onto adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302624 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2625 ioc->cached_fw, CAN_SLEEP)) < 0) {
2626 printk(MYIOC_s_WARN_FMT
2627 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002628 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 }
2630 }
2631
Kashyap, Desai71278192009-05-29 16:53:14 +05302632 /*
2633 * Put the controller into ready state (if its not already)
2634 */
2635 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {
2636 if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
2637 CAN_SLEEP)) {
2638 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)
2639 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit "
2640 "reset failed to put ioc in ready state!\n",
2641 ioc->name, __func__);
2642 } else
2643 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset "
2644 "failed!\n", ioc->name, __func__);
2645 }
2646
2647
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 /* Disable adapter interrupts! */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302649 synchronize_irq(ioc->pcidev->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2651 ioc->active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302652
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 /* Clear any lingering interrupt */
2654 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302655 CHIPREG_READ32(&ioc->chip->IntStatus);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656
2657 if (ioc->alloc != NULL) {
2658 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002659 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2660 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 pci_free_consistent(ioc->pcidev, sz,
2662 ioc->alloc, ioc->alloc_dma);
2663 ioc->reply_frames = NULL;
2664 ioc->req_frames = NULL;
2665 ioc->alloc = NULL;
2666 ioc->alloc_total -= sz;
2667 }
2668
2669 if (ioc->sense_buf_pool != NULL) {
2670 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2671 pci_free_consistent(ioc->pcidev, sz,
2672 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2673 ioc->sense_buf_pool = NULL;
2674 ioc->alloc_total -= sz;
2675 }
2676
2677 if (ioc->events != NULL){
2678 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2679 kfree(ioc->events);
2680 ioc->events = NULL;
2681 ioc->alloc_total -= sz;
2682 }
2683
Prakash, Sathya984621b2008-01-11 14:42:17 +05302684 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002686 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002687 mpt_inactive_raid_list_free(ioc);
2688 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002689 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002690 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002691 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692
2693 if (ioc->spi_data.pIocPg4 != NULL) {
2694 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302695 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 ioc->spi_data.pIocPg4,
2697 ioc->spi_data.IocPg4_dma);
2698 ioc->spi_data.pIocPg4 = NULL;
2699 ioc->alloc_total -= sz;
2700 }
2701
2702 if (ioc->ReqToChain != NULL) {
2703 kfree(ioc->ReqToChain);
2704 kfree(ioc->RequestNB);
2705 ioc->ReqToChain = NULL;
2706 }
2707
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002708 kfree(ioc->ChainToChain);
2709 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002710
2711 if (ioc->HostPageBuffer != NULL) {
2712 if((ret = mpt_host_page_access_control(ioc,
2713 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002714 printk(MYIOC_s_ERR_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302715 ": %s: host page buffers free failed (%d)!\n",
2716 ioc->name, __func__, ret);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002717 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302718 dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2719 "HostPageBuffer free @ %p, sz=%d bytes\n",
2720 ioc->name, ioc->HostPageBuffer,
2721 ioc->HostPageBuffer_sz));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002722 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002723 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002724 ioc->HostPageBuffer = NULL;
2725 ioc->HostPageBuffer_sz = 0;
2726 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2727 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728
Kashyap, Desai2f187862009-05-29 16:52:37 +05302729 pci_set_drvdata(ioc->pcidev, NULL);
2730}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002732/**
2733 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 * @ioc: Pointer to MPT adapter structure
2735 *
2736 * This routine unregisters h/w resources and frees all alloc'd memory
2737 * associated with a MPT adapter structure.
2738 */
2739static void
2740mpt_adapter_dispose(MPT_ADAPTER *ioc)
2741{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002742 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002744 if (ioc == NULL)
2745 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002747 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002749 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002751 if (ioc->pci_irq != -1) {
2752 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302753 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002754 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002755 ioc->pci_irq = -1;
2756 }
2757
2758 if (ioc->memmap != NULL) {
2759 iounmap(ioc->memmap);
2760 ioc->memmap = NULL;
2761 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302763 pci_disable_device(ioc->pcidev);
2764 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2765
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002767 if (ioc->mtrr_reg > 0) {
2768 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002769 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002770 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771#endif
2772
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002773 /* Zap the adapter lookup ptr! */
2774 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002776 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002777 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2778 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002779
2780 if (ioc->alt_ioc)
2781 ioc->alt_ioc->alt_ioc = NULL;
2782
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002783 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784}
2785
2786/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002787/**
2788 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 * @ioc: Pointer to MPT adapter structure
2790 */
2791static void
2792MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2793{
2794 int i = 0;
2795
2796 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302797 if (ioc->prod_name)
2798 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 printk("Capabilities={");
2800
2801 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2802 printk("Initiator");
2803 i++;
2804 }
2805
2806 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2807 printk("%sTarget", i ? "," : "");
2808 i++;
2809 }
2810
2811 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2812 printk("%sLAN", i ? "," : "");
2813 i++;
2814 }
2815
2816#if 0
2817 /*
2818 * This would probably evoke more questions than it's worth
2819 */
2820 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2821 printk("%sLogBusAddr", i ? "," : "");
2822 i++;
2823 }
2824#endif
2825
2826 printk("}\n");
2827}
2828
2829/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002830/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2832 * @ioc: Pointer to MPT_ADAPTER structure
2833 * @force: Force hard KickStart of IOC
2834 * @sleepFlag: Specifies whether the process can sleep
2835 *
2836 * Returns:
2837 * 1 - DIAG reset and READY
2838 * 0 - READY initially OR soft reset and READY
2839 * -1 - Any failure on KickStart
2840 * -2 - Msg Unit Reset Failed
2841 * -3 - IO Unit Reset Failed
2842 * -4 - IOC owned by a PEER
2843 */
2844static int
2845MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2846{
2847 u32 ioc_state;
2848 int statefault = 0;
2849 int cntdn;
2850 int hard_reset_done = 0;
2851 int r;
2852 int ii;
2853 int whoinit;
2854
2855 /* Get current [raw] IOC state */
2856 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002857 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858
2859 /*
2860 * Check to see if IOC got left/stuck in doorbell handshake
2861 * grip of death. If so, hard reset the IOC.
2862 */
2863 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2864 statefault = 1;
2865 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2866 ioc->name);
2867 }
2868
2869 /* Is it already READY? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302870 if (!statefault &&
2871 ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) {
2872 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2873 "IOC is in READY state\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 return 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302875 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876
2877 /*
2878 * Check to see if IOC is in FAULT state.
2879 */
2880 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2881 statefault = 2;
2882 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002883 ioc->name);
2884 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2885 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 }
2887
2888 /*
2889 * Hmmm... Did it get left operational?
2890 */
2891 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302892 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 ioc->name));
2894
2895 /* Check WhoInit.
2896 * If PCI Peer, exit.
2897 * Else, if no fault conditions are present, issue a MessageUnitReset
2898 * Else, fall through to KickStart case
2899 */
2900 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002901 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2902 "whoinit 0x%x statefault %d force %d\n",
2903 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 if (whoinit == MPI_WHOINIT_PCI_PEER)
2905 return -4;
2906 else {
2907 if ((statefault == 0 ) && (force == 0)) {
2908 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2909 return 0;
2910 }
2911 statefault = 3;
2912 }
2913 }
2914
2915 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2916 if (hard_reset_done < 0)
2917 return -1;
2918
2919 /*
2920 * Loop here waiting for IOC to come READY.
2921 */
2922 ii = 0;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002923 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924
2925 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2926 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2927 /*
2928 * BIOS or previous driver load left IOC in OP state.
2929 * Reset messaging FIFOs.
2930 */
2931 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2932 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2933 return -2;
2934 }
2935 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2936 /*
2937 * Something is wrong. Try to get IOC back
2938 * to a known state.
2939 */
2940 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2941 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2942 return -3;
2943 }
2944 }
2945
2946 ii++; cntdn--;
2947 if (!cntdn) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302948 printk(MYIOC_s_ERR_FMT
2949 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
2950 ioc->name, ioc_state, (int)((ii+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 return -ETIME;
2952 }
2953
2954 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002955 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 } else {
2957 mdelay (1); /* 1 msec delay */
2958 }
2959
2960 }
2961
2962 if (statefault < 3) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302963 printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name,
2964 statefault == 1 ? "stuck handshake" : "IOC FAULT");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 }
2966
2967 return hard_reset_done;
2968}
2969
2970/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002971/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 * mpt_GetIocState - Get the current state of a MPT adapter.
2973 * @ioc: Pointer to MPT_ADAPTER structure
2974 * @cooked: Request raw or cooked IOC state
2975 *
2976 * Returns all IOC Doorbell register bits if cooked==0, else just the
2977 * Doorbell bits in MPI_IOC_STATE_MASK.
2978 */
2979u32
2980mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2981{
2982 u32 s, sc;
2983
2984 /* Get! */
2985 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 sc = s & MPI_IOC_STATE_MASK;
2987
2988 /* Save! */
2989 ioc->last_state = sc;
2990
2991 return cooked ? sc : s;
2992}
2993
2994/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002995/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 * GetIocFacts - Send IOCFacts request to MPT adapter.
2997 * @ioc: Pointer to MPT_ADAPTER structure
2998 * @sleepFlag: Specifies whether the process can sleep
2999 * @reason: If recovery, only update facts.
3000 *
3001 * Returns 0 for success, non-zero for failure.
3002 */
3003static int
3004GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
3005{
3006 IOCFacts_t get_facts;
3007 IOCFactsReply_t *facts;
3008 int r;
3009 int req_sz;
3010 int reply_sz;
3011 int sz;
3012 u32 status, vv;
3013 u8 shiftFactor=1;
3014
3015 /* IOC *must* NOT be in RESET state! */
3016 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303017 printk(KERN_ERR MYNAM
3018 ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
3019 ioc->name, ioc->last_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 return -44;
3021 }
3022
3023 facts = &ioc->facts;
3024
3025 /* Destination (reply area)... */
3026 reply_sz = sizeof(*facts);
3027 memset(facts, 0, reply_sz);
3028
3029 /* Request area (get_facts on the stack right now!) */
3030 req_sz = sizeof(get_facts);
3031 memset(&get_facts, 0, req_sz);
3032
3033 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
3034 /* Assert: All other get_facts fields are zero! */
3035
Prakash, Sathya436ace72007-07-24 15:42:08 +05303036 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003037 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 ioc->name, req_sz, reply_sz));
3039
3040 /* No non-zero fields in the get_facts request are greater than
3041 * 1 byte in size, so we can just fire it off as is.
3042 */
3043 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3044 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3045 if (r != 0)
3046 return r;
3047
3048 /*
3049 * Now byte swap (GRRR) the necessary fields before any further
3050 * inspection of reply contents.
3051 *
3052 * But need to do some sanity checks on MsgLength (byte) field
3053 * to make sure we don't zero IOC's req_sz!
3054 */
3055 /* Did we get a valid reply? */
3056 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3057 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3058 /*
3059 * If not been here, done that, save off first WhoInit value
3060 */
3061 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3062 ioc->FirstWhoInit = facts->WhoInit;
3063 }
3064
3065 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3066 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3067 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3068 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3069 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003070 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 /* CHECKME! IOCStatus, IOCLogInfo */
3072
3073 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3074 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3075
3076 /*
3077 * FC f/w version changed between 1.1 and 1.2
3078 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3079 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3080 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303081 if (facts->MsgVersion < MPI_VERSION_01_02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 /*
3083 * Handle old FC f/w style, convert to new...
3084 */
3085 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3086 facts->FWVersion.Word =
3087 ((oldv<<12) & 0xFF000000) |
3088 ((oldv<<8) & 0x000FFF00);
3089 } else
3090 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3091
3092 facts->ProductID = le16_to_cpu(facts->ProductID);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303093
Eric Mooreb506ade2007-01-29 09:45:37 -07003094 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3095 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3096 ioc->ir_firmware = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303097
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 facts->CurrentHostMfaHighAddr =
3099 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3100 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3101 facts->CurrentSenseBufferHighAddr =
3102 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3103 facts->CurReplyFrameSize =
3104 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003105 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106
3107 /*
3108 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3109 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3110 * to 14 in MPI-1.01.0x.
3111 */
3112 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
Kashyap, Desai2f187862009-05-29 16:52:37 +05303113 facts->MsgVersion > MPI_VERSION_01_00) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3115 }
3116
3117 sz = facts->FWImageSize;
3118 if ( sz & 0x01 )
3119 sz += 1;
3120 if ( sz & 0x02 )
3121 sz += 2;
3122 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003123
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 if (!facts->RequestFrameSize) {
3125 /* Something is wrong! */
3126 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3127 ioc->name);
3128 return -55;
3129 }
3130
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003131 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 vv = ((63 / (sz * 4)) + 1) & 0x03;
3133 ioc->NB_for_64_byte_frame = vv;
3134 while ( sz )
3135 {
3136 shiftFactor++;
3137 sz = sz >> 1;
3138 }
3139 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303140 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003141 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3142 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003143
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3145 /*
3146 * Set values for this IOC's request & reply frame sizes,
3147 * and request & reply queue depths...
3148 */
3149 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3150 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3151 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3152 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3153
Prakash, Sathya436ace72007-07-24 15:42:08 +05303154 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303156 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157 ioc->name, ioc->req_sz, ioc->req_depth));
3158
3159 /* Get port facts! */
3160 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3161 return r;
3162 }
3163 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003164 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3166 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3167 RequestFrameSize)/sizeof(u32)));
3168 return -66;
3169 }
3170
3171 return 0;
3172}
3173
3174/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003175/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 * GetPortFacts - Send PortFacts request to MPT adapter.
3177 * @ioc: Pointer to MPT_ADAPTER structure
3178 * @portnum: Port number
3179 * @sleepFlag: Specifies whether the process can sleep
3180 *
3181 * Returns 0 for success, non-zero for failure.
3182 */
3183static int
3184GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3185{
3186 PortFacts_t get_pfacts;
3187 PortFactsReply_t *pfacts;
3188 int ii;
3189 int req_sz;
3190 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003191 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192
3193 /* IOC *must* NOT be in RESET state! */
3194 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003195 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3196 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 return -4;
3198 }
3199
3200 pfacts = &ioc->pfacts[portnum];
3201
3202 /* Destination (reply area)... */
3203 reply_sz = sizeof(*pfacts);
3204 memset(pfacts, 0, reply_sz);
3205
3206 /* Request area (get_pfacts on the stack right now!) */
3207 req_sz = sizeof(get_pfacts);
3208 memset(&get_pfacts, 0, req_sz);
3209
3210 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3211 get_pfacts.PortNumber = portnum;
3212 /* Assert: All other get_pfacts fields are zero! */
3213
Prakash, Sathya436ace72007-07-24 15:42:08 +05303214 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 ioc->name, portnum));
3216
3217 /* No non-zero fields in the get_pfacts request are greater than
3218 * 1 byte in size, so we can just fire it off as is.
3219 */
3220 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3221 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3222 if (ii != 0)
3223 return ii;
3224
3225 /* Did we get a valid reply? */
3226
3227 /* Now byte swap the necessary fields in the response. */
3228 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3229 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3230 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3231 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3232 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3233 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3234 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3235 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3236 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3237
Eric Moore793955f2007-01-29 09:42:20 -07003238 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3239 pfacts->MaxDevices;
3240 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3241 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3242
3243 /*
3244 * Place all the devices on channels
3245 *
3246 * (for debuging)
3247 */
3248 if (mpt_channel_mapping) {
3249 ioc->devices_per_bus = 1;
3250 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3251 }
3252
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 return 0;
3254}
3255
3256/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003257/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 * SendIocInit - Send IOCInit request to MPT adapter.
3259 * @ioc: Pointer to MPT_ADAPTER structure
3260 * @sleepFlag: Specifies whether the process can sleep
3261 *
3262 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3263 *
3264 * Returns 0 for success, non-zero for failure.
3265 */
3266static int
3267SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3268{
3269 IOCInit_t ioc_init;
3270 MPIDefaultReply_t init_reply;
3271 u32 state;
3272 int r;
3273 int count;
3274 int cntdn;
3275
3276 memset(&ioc_init, 0, sizeof(ioc_init));
3277 memset(&init_reply, 0, sizeof(init_reply));
3278
3279 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3280 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3281
3282 /* If we are in a recovery mode and we uploaded the FW image,
3283 * then this pointer is not NULL. Skip the upload a second time.
3284 * Set this flag if cached_fw set for either IOC.
3285 */
3286 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3287 ioc->upload_fw = 1;
3288 else
3289 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303290 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3292
Eric Moore793955f2007-01-29 09:42:20 -07003293 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3294 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303295
Prakash, Sathya436ace72007-07-24 15:42:08 +05303296 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003297 ioc->name, ioc->facts.MsgVersion));
3298 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3299 // set MsgVersion and HeaderVersion host driver was built with
3300 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3301 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003303 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3304 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3305 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3306 return -99;
3307 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3309
Kashyap, Desai2f187862009-05-29 16:52:37 +05303310 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 /* Save the upper 32-bits of the request
3312 * (reply) and sense buffers.
3313 */
3314 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3315 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3316 } else {
3317 /* Force 32-bit addressing */
3318 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3319 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3320 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003321
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3323 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003324 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3325 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326
Prakash, Sathya436ace72007-07-24 15:42:08 +05303327 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 ioc->name, &ioc_init));
3329
3330 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3331 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003332 if (r != 0) {
3333 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 return r;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336
3337 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003338 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 */
3340
Prakash, Sathya436ace72007-07-24 15:42:08 +05303341 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003343
3344 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3345 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003347 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348
3349 /* YIKES! SUPER IMPORTANT!!!
3350 * Poll IocState until _OPERATIONAL while IOC is doing
3351 * LoopInit and TargetDiscovery!
3352 */
3353 count = 0;
3354 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3355 state = mpt_GetIocState(ioc, 1);
3356 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3357 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003358 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 } else {
3360 mdelay(1);
3361 }
3362
3363 if (!cntdn) {
3364 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3365 ioc->name, (int)((count+5)/HZ));
3366 return -9;
3367 }
3368
3369 state = mpt_GetIocState(ioc, 1);
3370 count++;
3371 }
Eric Moore29dd3602007-09-14 18:46:51 -06003372 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 ioc->name, count));
3374
Eric Mooreba856d32006-07-11 17:34:01 -06003375 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 return r;
3377}
3378
3379/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003380/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 * SendPortEnable - Send PortEnable request to MPT adapter port.
3382 * @ioc: Pointer to MPT_ADAPTER structure
3383 * @portnum: Port number to enable
3384 * @sleepFlag: Specifies whether the process can sleep
3385 *
3386 * Send PortEnable to bring IOC to OPERATIONAL state.
3387 *
3388 * Returns 0 for success, non-zero for failure.
3389 */
3390static int
3391SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3392{
3393 PortEnable_t port_enable;
3394 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003395 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 int req_sz;
3397 int reply_sz;
3398
3399 /* Destination... */
3400 reply_sz = sizeof(MPIDefaultReply_t);
3401 memset(&reply_buf, 0, reply_sz);
3402
3403 req_sz = sizeof(PortEnable_t);
3404 memset(&port_enable, 0, req_sz);
3405
3406 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3407 port_enable.PortNumber = portnum;
3408/* port_enable.ChainOffset = 0; */
3409/* port_enable.MsgFlags = 0; */
3410/* port_enable.MsgContext = 0; */
3411
Prakash, Sathya436ace72007-07-24 15:42:08 +05303412 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 ioc->name, portnum, &port_enable));
3414
3415 /* RAID FW may take a long time to enable
3416 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003417 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003418 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3419 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3420 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003421 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003422 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3423 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3424 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003426 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427}
3428
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003429/**
3430 * mpt_alloc_fw_memory - allocate firmware memory
3431 * @ioc: Pointer to MPT_ADAPTER structure
3432 * @size: total FW bytes
3433 *
3434 * If memory has already been allocated, the same (cached) value
3435 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303436 *
3437 * Return 0 if successfull, or non-zero for failure
3438 **/
3439int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3441{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303442 int rc;
3443
3444 if (ioc->cached_fw) {
3445 rc = 0; /* use already allocated memory */
3446 goto out;
3447 }
3448 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3450 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303451 rc = 0;
3452 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303454 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3455 if (!ioc->cached_fw) {
3456 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3457 ioc->name);
3458 rc = -1;
3459 } else {
3460 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3461 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3462 ioc->alloc_total += size;
3463 rc = 0;
3464 }
3465 out:
3466 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303468
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003469/**
3470 * mpt_free_fw_memory - free firmware memory
3471 * @ioc: Pointer to MPT_ADAPTER structure
3472 *
3473 * If alt_img is NULL, delete from ioc structure.
3474 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303475 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476void
3477mpt_free_fw_memory(MPT_ADAPTER *ioc)
3478{
3479 int sz;
3480
Prakash, Sathya984621b2008-01-11 14:42:17 +05303481 if (!ioc->cached_fw)
3482 return;
3483
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303485 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3486 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003487 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303488 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490}
3491
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003493/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3495 * @ioc: Pointer to MPT_ADAPTER structure
3496 * @sleepFlag: Specifies whether the process can sleep
3497 *
3498 * Returns 0 for success, >0 for handshake failure
3499 * <0 for fw upload failure.
3500 *
3501 * Remark: If bound IOC and a successful FWUpload was performed
3502 * on the bound IOC, the second image is discarded
3503 * and memory is free'd. Both channels must upload to prevent
3504 * IOC from running in degraded mode.
3505 */
3506static int
3507mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3508{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509 u8 reply[sizeof(FWUploadReply_t)];
3510 FWUpload_t *prequest;
3511 FWUploadReply_t *preply;
3512 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 u32 flagsLength;
3514 int ii, sz, reply_sz;
3515 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303516 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517 /* If the image size is 0, we are done.
3518 */
3519 if ((sz = ioc->facts.FWImageSize) == 0)
3520 return 0;
3521
Prakash, Sathya984621b2008-01-11 14:42:17 +05303522 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3523 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524
Eric Moore29dd3602007-09-14 18:46:51 -06003525 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3526 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003527
Eric Moorebc6e0892007-09-29 10:16:28 -06003528 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3529 kzalloc(ioc->req_sz, GFP_KERNEL);
3530 if (!prequest) {
3531 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3532 "while allocating memory \n", ioc->name));
3533 mpt_free_fw_memory(ioc);
3534 return -ENOMEM;
3535 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536
Eric Moorebc6e0892007-09-29 10:16:28 -06003537 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538
3539 reply_sz = sizeof(reply);
3540 memset(preply, 0, reply_sz);
3541
3542 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3543 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3544
3545 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3546 ptcsge->DetailsLength = 12;
3547 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3548 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003549 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303552 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3553 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3554 ioc->SGE_size;
3555 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3556 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3557 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003558 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303560 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3561 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562
Kashyap, Desai2f187862009-05-29 16:52:37 +05303563 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
3564 "rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565
3566 cmdStatus = -EFAULT;
3567 if (ii == 0) {
3568 /* Handshake transfer was complete and successful.
3569 * Check the Reply Frame.
3570 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303571 int status;
3572 status = le16_to_cpu(preply->IOCStatus) &
3573 MPI_IOCSTATUS_MASK;
3574 if (status == MPI_IOCSTATUS_SUCCESS &&
3575 ioc->facts.FWImageSize ==
3576 le32_to_cpu(preply->ActualImageSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 cmdStatus = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303579 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 ioc->name, cmdStatus));
3581
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003582
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 if (cmdStatus) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303584 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
3585 "freeing image \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586 mpt_free_fw_memory(ioc);
3587 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003588 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589
3590 return cmdStatus;
3591}
3592
3593/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003594/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595 * mpt_downloadboot - DownloadBoot code
3596 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003597 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 * @sleepFlag: Specifies whether the process can sleep
3599 *
3600 * FwDownloadBoot requires Programmed IO access.
3601 *
3602 * Returns 0 for success
3603 * -1 FW Image size is 0
3604 * -2 No valid cached_fw Pointer
3605 * <0 for fw upload failure.
3606 */
3607static int
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003608mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 MpiExtImageHeader_t *pExtImage;
3611 u32 fwSize;
3612 u32 diag0val;
3613 int count;
3614 u32 *ptrFw;
3615 u32 diagRwData;
3616 u32 nextImage;
3617 u32 load_addr;
3618 u32 ioc_state=0;
3619
Prakash, Sathya436ace72007-07-24 15:42:08 +05303620 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003621 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003622
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3624 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3625 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3626 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3627 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3628 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3629
3630 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3631
3632 /* wait 1 msec */
3633 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003634 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 } else {
3636 mdelay (1);
3637 }
3638
3639 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3640 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3641
3642 for (count = 0; count < 30; count ++) {
3643 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3644 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303645 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 ioc->name, count));
3647 break;
3648 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003649 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003651 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 } else {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003653 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 }
3655 }
3656
3657 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303658 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003659 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660 ioc->name, diag0val));
3661 return -3;
3662 }
3663
3664 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3665 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3666 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3667 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3668 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3669 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3670
3671 /* Set the DiagRwEn and Disable ARM bits */
3672 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3673
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 fwSize = (pFwHeader->ImageSize + 3)/4;
3675 ptrFw = (u32 *) pFwHeader;
3676
3677 /* Write the LoadStartAddress to the DiagRw Address Register
3678 * using Programmed IO
3679 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003680 if (ioc->errata_flag_1064)
3681 pci_enable_io_access(ioc->pcidev);
3682
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303684 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685 ioc->name, pFwHeader->LoadStartAddress));
3686
Prakash, Sathya436ace72007-07-24 15:42:08 +05303687 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 ioc->name, fwSize*4, ptrFw));
3689 while (fwSize--) {
3690 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3691 }
3692
3693 nextImage = pFwHeader->NextImageHeaderOffset;
3694 while (nextImage) {
3695 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3696
3697 load_addr = pExtImage->LoadStartAddress;
3698
3699 fwSize = (pExtImage->ImageSize + 3) >> 2;
3700 ptrFw = (u32 *)pExtImage;
3701
Prakash, Sathya436ace72007-07-24 15:42:08 +05303702 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 +02003703 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3705
3706 while (fwSize--) {
3707 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3708 }
3709 nextImage = pExtImage->NextImageHeaderOffset;
3710 }
3711
3712 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303713 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3715
3716 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303717 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3719
3720 /* Clear the internal flash bad bit - autoincrementing register,
3721 * so must do two writes.
3722 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003723 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003724 /*
3725 * 1030 and 1035 H/W errata, workaround to access
3726 * the ClearFlashBadSignatureBit
3727 */
3728 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3729 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3730 diagRwData |= 0x40000000;
3731 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3732 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3733
3734 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3735 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3736 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3737 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3738
3739 /* wait 1 msec */
3740 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003741 msleep (1);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003742 } else {
3743 mdelay (1);
3744 }
3745 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003747 if (ioc->errata_flag_1064)
3748 pci_disable_io_access(ioc->pcidev);
3749
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303751 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003752 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753 ioc->name, diag0val));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003754 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303755 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756 ioc->name, diag0val));
3757 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3758
3759 /* Write 0xFF to reset the sequencer */
3760 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3761
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003762 if (ioc->bus_type == SAS) {
3763 ioc_state = mpt_GetIocState(ioc, 0);
3764 if ( (GetIocFacts(ioc, sleepFlag,
3765 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303766 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003767 ioc->name, ioc_state));
3768 return -EFAULT;
3769 }
3770 }
3771
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 for (count=0; count<HZ*20; count++) {
3773 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303774 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3775 "downloadboot successful! (count=%d) IocState=%x\n",
3776 ioc->name, count, ioc_state));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003777 if (ioc->bus_type == SAS) {
3778 return 0;
3779 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303781 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3782 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783 ioc->name));
3784 return -EFAULT;
3785 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303786 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3787 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788 ioc->name));
3789 return 0;
3790 }
3791 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003792 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 } else {
3794 mdelay (10);
3795 }
3796 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303797 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3798 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 return -EFAULT;
3800}
3801
3802/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003803/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804 * KickStart - Perform hard reset of MPT adapter.
3805 * @ioc: Pointer to MPT_ADAPTER structure
3806 * @force: Force hard reset
3807 * @sleepFlag: Specifies whether the process can sleep
3808 *
3809 * This routine places MPT adapter in diagnostic mode via the
3810 * WriteSequence register, and then performs a hard reset of adapter
3811 * via the Diagnostic register.
3812 *
3813 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3814 * or NO_SLEEP (interrupt thread, use mdelay)
3815 * force - 1 if doorbell active, board fault state
3816 * board operational, IOC_RECOVERY or
3817 * IOC_BRINGUP and there is an alt_ioc.
3818 * 0 else
3819 *
3820 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003821 * 1 - hard reset, READY
3822 * 0 - no reset due to History bit, READY
3823 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 * OR reset but failed to come READY
3825 * -2 - no reset, could not enter DIAG mode
3826 * -3 - reset but bad FW bit
3827 */
3828static int
3829KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3830{
3831 int hard_reset_done = 0;
3832 u32 ioc_state=0;
3833 int cnt,cntdn;
3834
Eric Moore29dd3602007-09-14 18:46:51 -06003835 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003836 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837 /* Always issue a Msg Unit Reset first. This will clear some
3838 * SCSI bus hang conditions.
3839 */
3840 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3841
3842 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003843 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844 } else {
3845 mdelay (1000);
3846 }
3847 }
3848
3849 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3850 if (hard_reset_done < 0)
3851 return hard_reset_done;
3852
Prakash, Sathya436ace72007-07-24 15:42:08 +05303853 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003854 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855
3856 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3857 for (cnt=0; cnt<cntdn; cnt++) {
3858 ioc_state = mpt_GetIocState(ioc, 1);
3859 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303860 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861 ioc->name, cnt));
3862 return hard_reset_done;
3863 }
3864 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003865 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 } else {
3867 mdelay (10);
3868 }
3869 }
3870
Eric Moore29dd3602007-09-14 18:46:51 -06003871 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3872 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 return -1;
3874}
3875
3876/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003877/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 * mpt_diag_reset - Perform hard reset of the adapter.
3879 * @ioc: Pointer to MPT_ADAPTER structure
3880 * @ignore: Set if to honor and clear to ignore
3881 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003882 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883 * else set to NO_SLEEP (use mdelay instead)
3884 *
3885 * This routine places the adapter in diagnostic mode via the
3886 * WriteSequence register and then performs a hard reset of adapter
3887 * via the Diagnostic register. Adapter should be in ready state
3888 * upon successful completion.
3889 *
3890 * Returns: 1 hard reset successful
3891 * 0 no reset performed because reset history bit set
3892 * -2 enabling diagnostic mode failed
3893 * -3 diagnostic reset failed
3894 */
3895static int
3896mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3897{
3898 u32 diag0val;
3899 u32 doorbell;
3900 int hard_reset_done = 0;
3901 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303903 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Kashyap, Desaid1306912009-08-05 12:53:51 +05303904 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905
Eric Moorecd2c6192007-01-29 09:47:47 -07003906 /* Clear any existing interrupts */
3907 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3908
Eric Moore87cf8982006-06-27 16:09:26 -06003909 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303910
3911 if (!ignore)
3912 return 0;
3913
Prakash, Sathya436ace72007-07-24 15:42:08 +05303914 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003915 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003916 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3917 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3918 if (sleepFlag == CAN_SLEEP)
3919 msleep(1);
3920 else
3921 mdelay(1);
3922
Kashyap, Desaid1306912009-08-05 12:53:51 +05303923 /*
3924 * Call each currently registered protocol IOC reset handler
3925 * with pre-reset indication.
3926 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3927 * MptResetHandlers[] registered yet.
3928 */
3929 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3930 if (MptResetHandlers[cb_idx])
3931 (*(MptResetHandlers[cb_idx]))(ioc,
3932 MPT_IOC_PRE_RESET);
3933 }
3934
Eric Moore87cf8982006-06-27 16:09:26 -06003935 for (count = 0; count < 60; count ++) {
3936 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3937 doorbell &= MPI_IOC_STATE_MASK;
3938
Prakash, Sathya436ace72007-07-24 15:42:08 +05303939 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003940 "looking for READY STATE: doorbell=%x"
3941 " count=%d\n",
3942 ioc->name, doorbell, count));
Kashyap, Desai2f187862009-05-29 16:52:37 +05303943
Eric Moore87cf8982006-06-27 16:09:26 -06003944 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003945 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003946 }
3947
3948 /* wait 1 sec */
3949 if (sleepFlag == CAN_SLEEP)
3950 msleep(1000);
3951 else
3952 mdelay(1000);
3953 }
3954 return -1;
3955 }
3956
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 /* Use "Diagnostic reset" method! (only thing available!) */
3958 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3959
Prakash, Sathya436ace72007-07-24 15:42:08 +05303960 if (ioc->debug_level & MPT_DEBUG) {
3961 if (ioc->alt_ioc)
3962 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3963 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303965 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966
3967 /* Do the reset if we are told to ignore the reset history
3968 * or if the reset history is 0
3969 */
3970 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3971 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3972 /* Write magic sequence to WriteSequence register
3973 * Loop until in diagnostic mode
3974 */
3975 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3976 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3977 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3978 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3979 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3980 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3981
3982 /* wait 100 msec */
3983 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003984 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985 } else {
3986 mdelay (100);
3987 }
3988
3989 count++;
3990 if (count > 20) {
3991 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3992 ioc->name, diag0val);
3993 return -2;
3994
3995 }
3996
3997 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3998
Prakash, Sathya436ace72007-07-24 15:42:08 +05303999 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 ioc->name, diag0val));
4001 }
4002
Prakash, Sathya436ace72007-07-24 15:42:08 +05304003 if (ioc->debug_level & MPT_DEBUG) {
4004 if (ioc->alt_ioc)
4005 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4006 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304008 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 /*
4010 * Disable the ARM (Bug fix)
4011 *
4012 */
4013 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004014 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015
4016 /*
4017 * Now hit the reset bit in the Diagnostic register
4018 * (THE BIG HAMMER!) (Clears DRWE bit).
4019 */
4020 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
4021 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304022 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 ioc->name));
4024
4025 /*
4026 * Call each currently registered protocol IOC reset handler
4027 * with pre-reset indication.
4028 * NOTE: If we're doing _IOC_BRINGUP, there can be no
4029 * MptResetHandlers[] registered yet.
4030 */
Kashyap, Desaid1306912009-08-05 12:53:51 +05304031 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
4032 if (MptResetHandlers[cb_idx]) {
4033 mpt_signal_reset(cb_idx,
4034 ioc, MPT_IOC_PRE_RESET);
4035 if (ioc->alt_ioc) {
4036 mpt_signal_reset(cb_idx,
4037 ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 }
4039 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040 }
4041
Eric Moore0ccdb002006-07-11 17:33:13 -06004042 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304043 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06004044 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304045 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4046 else
4047 cached_fw = NULL;
4048 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 /* If the DownloadBoot operation fails, the
4050 * IOC will be left unusable. This is a fatal error
4051 * case. _diag_reset will return < 0
4052 */
4053 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304054 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4056 break;
4057 }
4058
Prakash, Sathya436ace72007-07-24 15:42:08 +05304059 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304060 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 /* wait 1 sec */
4062 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004063 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004064 } else {
4065 mdelay (1000);
4066 }
4067 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304068 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004069 printk(MYIOC_s_WARN_FMT
4070 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071 }
4072
4073 } else {
4074 /* Wait for FW to reload and for board
4075 * to go to the READY state.
4076 * Maximum wait is 60 seconds.
4077 * If fail, no error will check again
4078 * with calling program.
4079 */
4080 for (count = 0; count < 60; count ++) {
4081 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4082 doorbell &= MPI_IOC_STATE_MASK;
4083
Kashyap, Desai2f187862009-05-29 16:52:37 +05304084 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4085 "looking for READY STATE: doorbell=%x"
4086 " count=%d\n", ioc->name, doorbell, count));
4087
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088 if (doorbell == MPI_IOC_STATE_READY) {
4089 break;
4090 }
4091
4092 /* wait 1 sec */
4093 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004094 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095 } else {
4096 mdelay (1000);
4097 }
4098 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05304099
4100 if (doorbell != MPI_IOC_STATE_READY)
4101 printk(MYIOC_s_ERR_FMT "Failed to come READY "
4102 "after reset! IocState=%x", ioc->name,
4103 doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104 }
4105 }
4106
4107 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304108 if (ioc->debug_level & MPT_DEBUG) {
4109 if (ioc->alt_ioc)
4110 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4111 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4112 ioc->name, diag0val, diag1val));
4113 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114
4115 /* Clear RESET_HISTORY bit! Place board in the
4116 * diagnostic mode to update the diag register.
4117 */
4118 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4119 count = 0;
4120 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4121 /* Write magic sequence to WriteSequence register
4122 * Loop until in diagnostic mode
4123 */
4124 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4125 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4126 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4127 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4128 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4129 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4130
4131 /* wait 100 msec */
4132 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004133 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134 } else {
4135 mdelay (100);
4136 }
4137
4138 count++;
4139 if (count > 20) {
4140 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4141 ioc->name, diag0val);
4142 break;
4143 }
4144 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4145 }
4146 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4147 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4148 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4149 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4150 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4151 ioc->name);
4152 }
4153
4154 /* Disable Diagnostic Mode
4155 */
4156 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4157
4158 /* Check FW reload status flags.
4159 */
4160 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4161 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4162 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4163 ioc->name, diag0val);
4164 return -3;
4165 }
4166
Prakash, Sathya436ace72007-07-24 15:42:08 +05304167 if (ioc->debug_level & MPT_DEBUG) {
4168 if (ioc->alt_ioc)
4169 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4170 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304172 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173
4174 /*
4175 * Reset flag that says we've enabled event notification
4176 */
4177 ioc->facts.EventState = 0;
4178
4179 if (ioc->alt_ioc)
4180 ioc->alt_ioc->facts.EventState = 0;
4181
4182 return hard_reset_done;
4183}
4184
4185/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004186/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187 * SendIocReset - Send IOCReset request to MPT adapter.
4188 * @ioc: Pointer to MPT_ADAPTER structure
4189 * @reset_type: reset type, expected values are
4190 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004191 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 *
4193 * Send IOCReset request to the MPT adapter.
4194 *
4195 * Returns 0 for success, non-zero for failure.
4196 */
4197static int
4198SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4199{
4200 int r;
4201 u32 state;
4202 int cntdn, count;
4203
Prakash, Sathya436ace72007-07-24 15:42:08 +05304204 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205 ioc->name, reset_type));
4206 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4207 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4208 return r;
4209
4210 /* FW ACK'd request, wait for READY state
4211 */
4212 count = 0;
4213 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4214
4215 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4216 cntdn--;
4217 count++;
4218 if (!cntdn) {
4219 if (sleepFlag != CAN_SLEEP)
4220 count *= 10;
4221
Kashyap, Desai2f187862009-05-29 16:52:37 +05304222 printk(MYIOC_s_ERR_FMT
4223 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
4224 ioc->name, state, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225 return -ETIME;
4226 }
4227
4228 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004229 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230 } else {
4231 mdelay (1); /* 1 msec delay */
4232 }
4233 }
4234
4235 /* TODO!
4236 * Cleanup all event stuff for this IOC; re-issue EventNotification
4237 * request if needed.
4238 */
4239 if (ioc->facts.Function)
4240 ioc->facts.EventState = 0;
4241
4242 return 0;
4243}
4244
4245/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004246/**
4247 * initChainBuffers - Allocate memory for and initialize chain buffers
4248 * @ioc: Pointer to MPT_ADAPTER structure
4249 *
4250 * Allocates memory for and initializes chain buffers,
4251 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 */
4253static int
4254initChainBuffers(MPT_ADAPTER *ioc)
4255{
4256 u8 *mem;
4257 int sz, ii, num_chain;
4258 int scale, num_sge, numSGE;
4259
4260 /* ReqToChain size must equal the req_depth
4261 * index = req_idx
4262 */
4263 if (ioc->ReqToChain == NULL) {
4264 sz = ioc->req_depth * sizeof(int);
4265 mem = kmalloc(sz, GFP_ATOMIC);
4266 if (mem == NULL)
4267 return -1;
4268
4269 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304270 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271 ioc->name, mem, sz));
4272 mem = kmalloc(sz, GFP_ATOMIC);
4273 if (mem == NULL)
4274 return -1;
4275
4276 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304277 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278 ioc->name, mem, sz));
4279 }
4280 for (ii = 0; ii < ioc->req_depth; ii++) {
4281 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4282 }
4283
4284 /* ChainToChain size must equal the total number
4285 * of chain buffers to be allocated.
4286 * index = chain_idx
4287 *
4288 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004289 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290 *
4291 * num_sge = num sge in request frame + last chain buffer
4292 * scale = num sge per chain buffer if no chain element
4293 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304294 scale = ioc->req_sz / ioc->SGE_size;
4295 if (ioc->sg_addr_size == sizeof(u64))
4296 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304298 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304300 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304302 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304304 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4305 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304307 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 ioc->name, num_sge, numSGE));
4309
Kashyap, Desai2f187862009-05-29 16:52:37 +05304310 if (ioc->bus_type == FC) {
4311 if (numSGE > MPT_SCSI_FC_SG_DEPTH)
4312 numSGE = MPT_SCSI_FC_SG_DEPTH;
4313 } else {
4314 if (numSGE > MPT_SCSI_SG_DEPTH)
4315 numSGE = MPT_SCSI_SG_DEPTH;
4316 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317
4318 num_chain = 1;
4319 while (numSGE - num_sge > 0) {
4320 num_chain++;
4321 num_sge += (scale - 1);
4322 }
4323 num_chain++;
4324
Prakash, Sathya436ace72007-07-24 15:42:08 +05304325 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326 ioc->name, numSGE, num_sge, num_chain));
4327
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004328 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329 num_chain *= MPT_SCSI_CAN_QUEUE;
Anatolij Gustschinf1053a72009-12-12 14:52:21 +01004330 else if (ioc->bus_type == SAS)
4331 num_chain *= MPT_SAS_CAN_QUEUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 else
4333 num_chain *= MPT_FC_CAN_QUEUE;
4334
4335 ioc->num_chain = num_chain;
4336
4337 sz = num_chain * sizeof(int);
4338 if (ioc->ChainToChain == NULL) {
4339 mem = kmalloc(sz, GFP_ATOMIC);
4340 if (mem == NULL)
4341 return -1;
4342
4343 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304344 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 ioc->name, mem, sz));
4346 } else {
4347 mem = (u8 *) ioc->ChainToChain;
4348 }
4349 memset(mem, 0xFF, sz);
4350 return num_chain;
4351}
4352
4353/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004354/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4356 * @ioc: Pointer to MPT_ADAPTER structure
4357 *
4358 * This routine allocates memory for the MPT reply and request frame
4359 * pools (if necessary), and primes the IOC reply FIFO with
4360 * reply frames.
4361 *
4362 * Returns 0 for success, non-zero for failure.
4363 */
4364static int
4365PrimeIocFifos(MPT_ADAPTER *ioc)
4366{
4367 MPT_FRAME_HDR *mf;
4368 unsigned long flags;
4369 dma_addr_t alloc_dma;
4370 u8 *mem;
4371 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304372 u64 dma_mask;
4373
4374 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375
4376 /* Prime reply FIFO... */
4377
4378 if (ioc->reply_frames == NULL) {
4379 if ( (num_chain = initChainBuffers(ioc)) < 0)
4380 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304381 /*
4382 * 1078 errata workaround for the 36GB limitation
4383 */
4384 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
Andrew Morton8e20ce92009-06-18 16:49:17 -07004385 ioc->dma_mask > DMA_BIT_MASK(35)) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304386 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4387 && !pci_set_consistent_dma_mask(ioc->pcidev,
4388 DMA_BIT_MASK(32))) {
Andrew Morton8e20ce92009-06-18 16:49:17 -07004389 dma_mask = DMA_BIT_MASK(35);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304390 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4391 "setting 35 bit addressing for "
4392 "Request/Reply/Chain and Sense Buffers\n",
4393 ioc->name));
4394 } else {
4395 /*Reseting DMA mask to 64 bit*/
4396 pci_set_dma_mask(ioc->pcidev,
4397 DMA_BIT_MASK(64));
4398 pci_set_consistent_dma_mask(ioc->pcidev,
4399 DMA_BIT_MASK(64));
4400
4401 printk(MYIOC_s_ERR_FMT
4402 "failed setting 35 bit addressing for "
4403 "Request/Reply/Chain and Sense Buffers\n",
4404 ioc->name);
4405 return -1;
4406 }
4407 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408
4409 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304410 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304412 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413 ioc->name, reply_sz, reply_sz));
4414
4415 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304416 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304418 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 ioc->name, sz, sz));
4420 total_size += sz;
4421
4422 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304423 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304425 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426 ioc->name, sz, sz, num_chain));
4427
4428 total_size += sz;
4429 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4430 if (mem == NULL) {
4431 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4432 ioc->name);
4433 goto out_fail;
4434 }
4435
Prakash, Sathya436ace72007-07-24 15:42:08 +05304436 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4438
4439 memset(mem, 0, total_size);
4440 ioc->alloc_total += total_size;
4441 ioc->alloc = mem;
4442 ioc->alloc_dma = alloc_dma;
4443 ioc->alloc_sz = total_size;
4444 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4445 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4446
Prakash, Sathya436ace72007-07-24 15:42:08 +05304447 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004448 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4449
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 alloc_dma += reply_sz;
4451 mem += reply_sz;
4452
4453 /* Request FIFO - WE manage this! */
4454
4455 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4456 ioc->req_frames_dma = alloc_dma;
4457
Prakash, Sathya436ace72007-07-24 15:42:08 +05304458 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459 ioc->name, mem, (void *)(ulong)alloc_dma));
4460
4461 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4462
4463#if defined(CONFIG_MTRR) && 0
4464 /*
4465 * Enable Write Combining MTRR for IOC's memory region.
4466 * (at least as much as we can; "size and base must be
4467 * multiples of 4 kiB"
4468 */
4469 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4470 sz,
4471 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304472 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 ioc->name, ioc->req_frames_dma, sz));
4474#endif
4475
4476 for (i = 0; i < ioc->req_depth; i++) {
4477 alloc_dma += ioc->req_sz;
4478 mem += ioc->req_sz;
4479 }
4480
4481 ioc->ChainBuffer = mem;
4482 ioc->ChainBufferDMA = alloc_dma;
4483
Prakash, Sathya436ace72007-07-24 15:42:08 +05304484 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4486
4487 /* Initialize the free chain Q.
4488 */
4489
4490 INIT_LIST_HEAD(&ioc->FreeChainQ);
4491
4492 /* Post the chain buffers to the FreeChainQ.
4493 */
4494 mem = (u8 *)ioc->ChainBuffer;
4495 for (i=0; i < num_chain; i++) {
4496 mf = (MPT_FRAME_HDR *) mem;
4497 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4498 mem += ioc->req_sz;
4499 }
4500
4501 /* Initialize Request frames linked list
4502 */
4503 alloc_dma = ioc->req_frames_dma;
4504 mem = (u8 *) ioc->req_frames;
4505
4506 spin_lock_irqsave(&ioc->FreeQlock, flags);
4507 INIT_LIST_HEAD(&ioc->FreeQ);
4508 for (i = 0; i < ioc->req_depth; i++) {
4509 mf = (MPT_FRAME_HDR *) mem;
4510
4511 /* Queue REQUESTs *internally*! */
4512 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4513
4514 mem += ioc->req_sz;
4515 }
4516 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4517
4518 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4519 ioc->sense_buf_pool =
4520 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4521 if (ioc->sense_buf_pool == NULL) {
4522 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4523 ioc->name);
4524 goto out_fail;
4525 }
4526
4527 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4528 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304529 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4531
4532 }
4533
4534 /* Post Reply frames to FIFO
4535 */
4536 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304537 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004538 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4539
4540 for (i = 0; i < ioc->reply_depth; i++) {
4541 /* Write each address to the IOC! */
4542 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4543 alloc_dma += ioc->reply_sz;
4544 }
4545
Andrew Morton8e20ce92009-06-18 16:49:17 -07004546 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304547 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4548 ioc->dma_mask))
4549 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4550 "restoring 64 bit addressing\n", ioc->name));
4551
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552 return 0;
4553
4554out_fail:
Kashyap, Desai2f187862009-05-29 16:52:37 +05304555
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556 if (ioc->alloc != NULL) {
4557 sz = ioc->alloc_sz;
4558 pci_free_consistent(ioc->pcidev,
4559 sz,
4560 ioc->alloc, ioc->alloc_dma);
4561 ioc->reply_frames = NULL;
4562 ioc->req_frames = NULL;
4563 ioc->alloc_total -= sz;
4564 }
4565 if (ioc->sense_buf_pool != NULL) {
4566 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4567 pci_free_consistent(ioc->pcidev,
4568 sz,
4569 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4570 ioc->sense_buf_pool = NULL;
4571 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304572
Andrew Morton8e20ce92009-06-18 16:49:17 -07004573 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304574 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4575 DMA_BIT_MASK(64)))
4576 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4577 "restoring 64 bit addressing\n", ioc->name));
4578
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579 return -1;
4580}
4581
4582/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4583/**
4584 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4585 * from IOC via doorbell handshake method.
4586 * @ioc: Pointer to MPT_ADAPTER structure
4587 * @reqBytes: Size of the request in bytes
4588 * @req: Pointer to MPT request frame
4589 * @replyBytes: Expected size of the reply in bytes
4590 * @u16reply: Pointer to area where reply should be written
4591 * @maxwait: Max wait time for a reply (in seconds)
4592 * @sleepFlag: Specifies whether the process can sleep
4593 *
4594 * NOTES: It is the callers responsibility to byte-swap fields in the
4595 * request which are greater than 1 byte in size. It is also the
4596 * callers responsibility to byte-swap response fields which are
4597 * greater than 1 byte in size.
4598 *
4599 * Returns 0 for success, non-zero for failure.
4600 */
4601static int
4602mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004603 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604{
4605 MPIDefaultReply_t *mptReply;
4606 int failcnt = 0;
4607 int t;
4608
4609 /*
4610 * Get ready to cache a handshake reply
4611 */
4612 ioc->hs_reply_idx = 0;
4613 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4614 mptReply->MsgLength = 0;
4615
4616 /*
4617 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4618 * then tell IOC that we want to handshake a request of N words.
4619 * (WRITE u32val to Doorbell reg).
4620 */
4621 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4622 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4623 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4624 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4625
4626 /*
4627 * Wait for IOC's doorbell handshake int
4628 */
4629 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4630 failcnt++;
4631
Prakash, Sathya436ace72007-07-24 15:42:08 +05304632 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4634
4635 /* Read doorbell and check for active bit */
4636 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4637 return -1;
4638
4639 /*
4640 * Clear doorbell int (WRITE 0 to IntStatus reg),
4641 * then wait for IOC to ACKnowledge that it's ready for
4642 * our handshake request.
4643 */
4644 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4645 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4646 failcnt++;
4647
4648 if (!failcnt) {
4649 int ii;
4650 u8 *req_as_bytes = (u8 *) req;
4651
4652 /*
4653 * Stuff request words via doorbell handshake,
4654 * with ACK from IOC for each.
4655 */
4656 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4657 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4658 (req_as_bytes[(ii*4) + 1] << 8) |
4659 (req_as_bytes[(ii*4) + 2] << 16) |
4660 (req_as_bytes[(ii*4) + 3] << 24));
4661
4662 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4663 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4664 failcnt++;
4665 }
4666
Prakash, Sathya436ace72007-07-24 15:42:08 +05304667 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004668 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669
Prakash, Sathya436ace72007-07-24 15:42:08 +05304670 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4672
4673 /*
4674 * Wait for completion of doorbell handshake reply from the IOC
4675 */
4676 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4677 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004678
Prakash, Sathya436ace72007-07-24 15:42:08 +05304679 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4681
4682 /*
4683 * Copy out the cached reply...
4684 */
4685 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4686 u16reply[ii] = ioc->hs_reply[ii];
4687 } else {
4688 return -99;
4689 }
4690
4691 return -failcnt;
4692}
4693
4694/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004695/**
4696 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697 * @ioc: Pointer to MPT_ADAPTER structure
4698 * @howlong: How long to wait (in seconds)
4699 * @sleepFlag: Specifies whether the process can sleep
4700 *
4701 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004702 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4703 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704 *
4705 * Returns a negative value on failure, else wait loop count.
4706 */
4707static int
4708WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4709{
4710 int cntdn;
4711 int count = 0;
4712 u32 intstat=0;
4713
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004714 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715
4716 if (sleepFlag == CAN_SLEEP) {
4717 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004718 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4720 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4721 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722 count++;
4723 }
4724 } else {
4725 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004726 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4728 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4729 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730 count++;
4731 }
4732 }
4733
4734 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304735 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736 ioc->name, count));
4737 return count;
4738 }
4739
4740 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4741 ioc->name, count, intstat);
4742 return -1;
4743}
4744
4745/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004746/**
4747 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748 * @ioc: Pointer to MPT_ADAPTER structure
4749 * @howlong: How long to wait (in seconds)
4750 * @sleepFlag: Specifies whether the process can sleep
4751 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004752 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4753 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754 *
4755 * Returns a negative value on failure, else wait loop count.
4756 */
4757static int
4758WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4759{
4760 int cntdn;
4761 int count = 0;
4762 u32 intstat=0;
4763
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004764 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 if (sleepFlag == CAN_SLEEP) {
4766 while (--cntdn) {
4767 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4768 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4769 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004770 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 count++;
4772 }
4773 } else {
4774 while (--cntdn) {
4775 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4776 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4777 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004778 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 count++;
4780 }
4781 }
4782
4783 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304784 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785 ioc->name, count, howlong));
4786 return count;
4787 }
4788
4789 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4790 ioc->name, count, intstat);
4791 return -1;
4792}
4793
4794/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004795/**
4796 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 * @ioc: Pointer to MPT_ADAPTER structure
4798 * @howlong: How long to wait (in seconds)
4799 * @sleepFlag: Specifies whether the process can sleep
4800 *
4801 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4802 * Reply is cached to IOC private area large enough to hold a maximum
4803 * of 128 bytes of reply data.
4804 *
4805 * Returns a negative value on failure, else size of reply in WORDS.
4806 */
4807static int
4808WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4809{
4810 int u16cnt = 0;
4811 int failcnt = 0;
4812 int t;
4813 u16 *hs_reply = ioc->hs_reply;
4814 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4815 u16 hword;
4816
4817 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4818
4819 /*
4820 * Get first two u16's so we can look at IOC's intended reply MsgLength
4821 */
4822 u16cnt=0;
4823 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4824 failcnt++;
4825 } else {
4826 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4827 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4828 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4829 failcnt++;
4830 else {
4831 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4832 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4833 }
4834 }
4835
Prakash, Sathya436ace72007-07-24 15:42:08 +05304836 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004837 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4839
4840 /*
4841 * If no error (and IOC said MsgLength is > 0), piece together
4842 * reply 16 bits at a time.
4843 */
4844 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4845 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4846 failcnt++;
4847 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4848 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004849 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 hs_reply[u16cnt] = hword;
4851 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4852 }
4853
4854 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4855 failcnt++;
4856 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4857
4858 if (failcnt) {
4859 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4860 ioc->name);
4861 return -failcnt;
4862 }
4863#if 0
4864 else if (u16cnt != (2 * mptReply->MsgLength)) {
4865 return -101;
4866 }
4867 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4868 return -102;
4869 }
4870#endif
4871
Prakash, Sathya436ace72007-07-24 15:42:08 +05304872 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004873 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874
Prakash, Sathya436ace72007-07-24 15:42:08 +05304875 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876 ioc->name, t, u16cnt/2));
4877 return u16cnt/2;
4878}
4879
4880/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004881/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882 * GetLanConfigPages - Fetch LANConfig pages.
4883 * @ioc: Pointer to MPT_ADAPTER structure
4884 *
4885 * Return: 0 for success
4886 * -ENOMEM if no memory available
4887 * -EPERM if not allowed due to ISR context
4888 * -EAGAIN if no msg frames currently available
4889 * -EFAULT for non-successful reply or no reply (timeout)
4890 */
4891static int
4892GetLanConfigPages(MPT_ADAPTER *ioc)
4893{
4894 ConfigPageHeader_t hdr;
4895 CONFIGPARMS cfg;
4896 LANPage0_t *ppage0_alloc;
4897 dma_addr_t page0_dma;
4898 LANPage1_t *ppage1_alloc;
4899 dma_addr_t page1_dma;
4900 int rc = 0;
4901 int data_sz;
4902 int copy_sz;
4903
4904 /* Get LAN Page 0 header */
4905 hdr.PageVersion = 0;
4906 hdr.PageLength = 0;
4907 hdr.PageNumber = 0;
4908 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004909 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910 cfg.physAddr = -1;
4911 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4912 cfg.dir = 0;
4913 cfg.pageAddr = 0;
4914 cfg.timeout = 0;
4915
4916 if ((rc = mpt_config(ioc, &cfg)) != 0)
4917 return rc;
4918
4919 if (hdr.PageLength > 0) {
4920 data_sz = hdr.PageLength * 4;
4921 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4922 rc = -ENOMEM;
4923 if (ppage0_alloc) {
4924 memset((u8 *)ppage0_alloc, 0, data_sz);
4925 cfg.physAddr = page0_dma;
4926 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4927
4928 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4929 /* save the data */
4930 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4931 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4932
4933 }
4934
4935 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4936
4937 /* FIXME!
4938 * Normalize endianness of structure data,
4939 * by byte-swapping all > 1 byte fields!
4940 */
4941
4942 }
4943
4944 if (rc)
4945 return rc;
4946 }
4947
4948 /* Get LAN Page 1 header */
4949 hdr.PageVersion = 0;
4950 hdr.PageLength = 0;
4951 hdr.PageNumber = 1;
4952 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004953 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954 cfg.physAddr = -1;
4955 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4956 cfg.dir = 0;
4957 cfg.pageAddr = 0;
4958
4959 if ((rc = mpt_config(ioc, &cfg)) != 0)
4960 return rc;
4961
4962 if (hdr.PageLength == 0)
4963 return 0;
4964
4965 data_sz = hdr.PageLength * 4;
4966 rc = -ENOMEM;
4967 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4968 if (ppage1_alloc) {
4969 memset((u8 *)ppage1_alloc, 0, data_sz);
4970 cfg.physAddr = page1_dma;
4971 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4972
4973 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4974 /* save the data */
4975 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4976 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4977 }
4978
4979 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4980
4981 /* FIXME!
4982 * Normalize endianness of structure data,
4983 * by byte-swapping all > 1 byte fields!
4984 */
4985
4986 }
4987
4988 return rc;
4989}
4990
4991/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004992/**
4993 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004994 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004995 * @persist_opcode: see below
4996 *
4997 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4998 * devices not currently present.
4999 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
5000 *
5001 * NOTE: Don't use not this function during interrupt time.
5002 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005003 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005004 */
5005
5006/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5007int
5008mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
5009{
5010 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
5011 SasIoUnitControlReply_t *sasIoUnitCntrReply;
5012 MPT_FRAME_HDR *mf = NULL;
5013 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305014 int ret = 0;
5015 unsigned long timeleft;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005016
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305017 mutex_lock(&ioc->mptbase_cmds.mutex);
5018
5019 /* init the internal cmd struct */
5020 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
5021 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005022
5023 /* insure garbage is not sent to fw */
5024 switch(persist_opcode) {
5025
5026 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
5027 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
5028 break;
5029
5030 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305031 ret = -1;
5032 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005033 }
5034
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305035 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
5036 __func__, persist_opcode);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005037
5038 /* Get a MF for this command.
5039 */
5040 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305041 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
5042 ret = -1;
5043 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005044 }
5045
5046 mpi_hdr = (MPIHeader_t *) mf;
5047 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
5048 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
5049 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
5050 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
5051 sasIoUnitCntrReq->Operation = persist_opcode;
5052
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005053 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305054 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
5055 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
5056 ret = -ETIME;
5057 printk(KERN_DEBUG "%s: failed\n", __func__);
5058 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
5059 goto out;
5060 if (!timeleft) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09005061 printk(MYIOC_s_WARN_FMT
5062 "Issuing Reset from %s!!, doorbell=0x%08x\n",
5063 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05305064 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305065 mpt_free_msg_frame(ioc, mf);
5066 }
5067 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005068 }
5069
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305070 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
5071 ret = -1;
5072 goto out;
5073 }
5074
5075 sasIoUnitCntrReply =
5076 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5077 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5078 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5079 __func__, sasIoUnitCntrReply->IOCStatus,
5080 sasIoUnitCntrReply->IOCLogInfo);
5081 printk(KERN_DEBUG "%s: failed\n", __func__);
5082 ret = -1;
5083 } else
5084 printk(KERN_DEBUG "%s: success\n", __func__);
5085 out:
5086
5087 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5088 mutex_unlock(&ioc->mptbase_cmds.mutex);
5089 return ret;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005090}
5091
5092/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005093
5094static void
5095mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5096 MpiEventDataRaid_t * pRaidEventData)
5097{
5098 int volume;
5099 int reason;
5100 int disk;
5101 int status;
5102 int flags;
5103 int state;
5104
5105 volume = pRaidEventData->VolumeID;
5106 reason = pRaidEventData->ReasonCode;
5107 disk = pRaidEventData->PhysDiskNum;
5108 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5109 flags = (status >> 0) & 0xff;
5110 state = (status >> 8) & 0xff;
5111
5112 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5113 return;
5114 }
5115
5116 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5117 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5118 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005119 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5120 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005121 } else {
5122 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5123 ioc->name, volume);
5124 }
5125
5126 switch(reason) {
5127 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5128 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5129 ioc->name);
5130 break;
5131
5132 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5133
5134 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5135 ioc->name);
5136 break;
5137
5138 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5139 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5140 ioc->name);
5141 break;
5142
5143 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5144 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5145 ioc->name,
5146 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5147 ? "optimal"
5148 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5149 ? "degraded"
5150 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5151 ? "failed"
5152 : "state unknown",
5153 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5154 ? ", enabled" : "",
5155 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5156 ? ", quiesced" : "",
5157 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5158 ? ", resync in progress" : "" );
5159 break;
5160
5161 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5162 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5163 ioc->name, disk);
5164 break;
5165
5166 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5167 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5168 ioc->name);
5169 break;
5170
5171 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5172 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5173 ioc->name);
5174 break;
5175
5176 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5177 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5178 ioc->name);
5179 break;
5180
5181 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5182 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5183 ioc->name,
5184 state == MPI_PHYSDISK0_STATUS_ONLINE
5185 ? "online"
5186 : state == MPI_PHYSDISK0_STATUS_MISSING
5187 ? "missing"
5188 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5189 ? "not compatible"
5190 : state == MPI_PHYSDISK0_STATUS_FAILED
5191 ? "failed"
5192 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5193 ? "initializing"
5194 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5195 ? "offline requested"
5196 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5197 ? "failed requested"
5198 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5199 ? "offline"
5200 : "state unknown",
5201 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5202 ? ", out of sync" : "",
5203 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5204 ? ", quiesced" : "" );
5205 break;
5206
5207 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5208 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5209 ioc->name, disk);
5210 break;
5211
5212 case MPI_EVENT_RAID_RC_SMART_DATA:
5213 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5214 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5215 break;
5216
5217 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5218 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5219 ioc->name, disk);
5220 break;
5221 }
5222}
5223
5224/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005225/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5227 * @ioc: Pointer to MPT_ADAPTER structure
5228 *
5229 * Returns: 0 for success
5230 * -ENOMEM if no memory available
5231 * -EPERM if not allowed due to ISR context
5232 * -EAGAIN if no msg frames currently available
5233 * -EFAULT for non-successful reply or no reply (timeout)
5234 */
5235static int
5236GetIoUnitPage2(MPT_ADAPTER *ioc)
5237{
5238 ConfigPageHeader_t hdr;
5239 CONFIGPARMS cfg;
5240 IOUnitPage2_t *ppage_alloc;
5241 dma_addr_t page_dma;
5242 int data_sz;
5243 int rc;
5244
5245 /* Get the page header */
5246 hdr.PageVersion = 0;
5247 hdr.PageLength = 0;
5248 hdr.PageNumber = 2;
5249 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005250 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251 cfg.physAddr = -1;
5252 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5253 cfg.dir = 0;
5254 cfg.pageAddr = 0;
5255 cfg.timeout = 0;
5256
5257 if ((rc = mpt_config(ioc, &cfg)) != 0)
5258 return rc;
5259
5260 if (hdr.PageLength == 0)
5261 return 0;
5262
5263 /* Read the config page */
5264 data_sz = hdr.PageLength * 4;
5265 rc = -ENOMEM;
5266 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5267 if (ppage_alloc) {
5268 memset((u8 *)ppage_alloc, 0, data_sz);
5269 cfg.physAddr = page_dma;
5270 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5271
5272 /* If Good, save data */
5273 if ((rc = mpt_config(ioc, &cfg)) == 0)
5274 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5275
5276 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5277 }
5278
5279 return rc;
5280}
5281
5282/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005283/**
5284 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005285 * @ioc: Pointer to a Adapter Strucutre
5286 * @portnum: IOC port number
5287 *
5288 * Return: -EFAULT if read of config page header fails
5289 * or if no nvram
5290 * If read of SCSI Port Page 0 fails,
5291 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5292 * Adapter settings: async, narrow
5293 * Return 1
5294 * If read of SCSI Port Page 2 fails,
5295 * Adapter settings valid
5296 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5297 * Return 1
5298 * Else
5299 * Both valid
5300 * Return 0
5301 * CHECK - what type of locking mechanisms should be used????
5302 */
5303static int
5304mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5305{
5306 u8 *pbuf;
5307 dma_addr_t buf_dma;
5308 CONFIGPARMS cfg;
5309 ConfigPageHeader_t header;
5310 int ii;
5311 int data, rc = 0;
5312
5313 /* Allocate memory
5314 */
5315 if (!ioc->spi_data.nvram) {
5316 int sz;
5317 u8 *mem;
5318 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5319 mem = kmalloc(sz, GFP_ATOMIC);
5320 if (mem == NULL)
5321 return -EFAULT;
5322
5323 ioc->spi_data.nvram = (int *) mem;
5324
Prakash, Sathya436ace72007-07-24 15:42:08 +05305325 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005326 ioc->name, ioc->spi_data.nvram, sz));
5327 }
5328
5329 /* Invalidate NVRAM information
5330 */
5331 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5332 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5333 }
5334
5335 /* Read SPP0 header, allocate memory, then read page.
5336 */
5337 header.PageVersion = 0;
5338 header.PageLength = 0;
5339 header.PageNumber = 0;
5340 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005341 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342 cfg.physAddr = -1;
5343 cfg.pageAddr = portnum;
5344 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5345 cfg.dir = 0;
5346 cfg.timeout = 0; /* use default */
5347 if (mpt_config(ioc, &cfg) != 0)
5348 return -EFAULT;
5349
5350 if (header.PageLength > 0) {
5351 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5352 if (pbuf) {
5353 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5354 cfg.physAddr = buf_dma;
5355 if (mpt_config(ioc, &cfg) != 0) {
5356 ioc->spi_data.maxBusWidth = MPT_NARROW;
5357 ioc->spi_data.maxSyncOffset = 0;
5358 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5359 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5360 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305361 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5362 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005363 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005364 } else {
5365 /* Save the Port Page 0 data
5366 */
5367 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5368 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5369 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5370
5371 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5372 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005373 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5374 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375 ioc->name, pPP0->Capabilities));
5376 }
5377 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5378 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5379 if (data) {
5380 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5381 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5382 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305383 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5384 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005385 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 } else {
5387 ioc->spi_data.maxSyncOffset = 0;
5388 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5389 }
5390
5391 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5392
5393 /* Update the minSyncFactor based on bus type.
5394 */
5395 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5396 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5397
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005398 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305400 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5401 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005402 ioc->name, ioc->spi_data.minSyncFactor));
5403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 }
5405 }
5406 if (pbuf) {
5407 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5408 }
5409 }
5410 }
5411
5412 /* SCSI Port Page 2 - Read the header then the page.
5413 */
5414 header.PageVersion = 0;
5415 header.PageLength = 0;
5416 header.PageNumber = 2;
5417 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005418 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419 cfg.physAddr = -1;
5420 cfg.pageAddr = portnum;
5421 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5422 cfg.dir = 0;
5423 if (mpt_config(ioc, &cfg) != 0)
5424 return -EFAULT;
5425
5426 if (header.PageLength > 0) {
5427 /* Allocate memory and read SCSI Port Page 2
5428 */
5429 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5430 if (pbuf) {
5431 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5432 cfg.physAddr = buf_dma;
5433 if (mpt_config(ioc, &cfg) != 0) {
5434 /* Nvram data is left with INVALID mark
5435 */
5436 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005437 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5438
5439 /* This is an ATTO adapter, read Page2 accordingly
5440 */
5441 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5442 ATTODeviceInfo_t *pdevice = NULL;
5443 u16 ATTOFlags;
5444
5445 /* Save the Port Page 2 data
5446 * (reformat into a 32bit quantity)
5447 */
5448 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5449 pdevice = &pPP2->DeviceSettings[ii];
5450 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5451 data = 0;
5452
5453 /* Translate ATTO device flags to LSI format
5454 */
5455 if (ATTOFlags & ATTOFLAG_DISC)
5456 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5457 if (ATTOFlags & ATTOFLAG_ID_ENB)
5458 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5459 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5460 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5461 if (ATTOFlags & ATTOFLAG_TAGGED)
5462 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5463 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5464 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5465
5466 data = (data << 16) | (pdevice->Period << 8) | 10;
5467 ioc->spi_data.nvram[ii] = data;
5468 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469 } else {
5470 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5471 MpiDeviceInfo_t *pdevice = NULL;
5472
Moore, Ericd8e925d2006-01-16 18:53:06 -07005473 /*
5474 * Save "Set to Avoid SCSI Bus Resets" flag
5475 */
5476 ioc->spi_data.bus_reset =
5477 (le32_to_cpu(pPP2->PortFlags) &
5478 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5479 0 : 1 ;
5480
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481 /* Save the Port Page 2 data
5482 * (reformat into a 32bit quantity)
5483 */
5484 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5485 ioc->spi_data.PortFlags = data;
5486 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5487 pdevice = &pPP2->DeviceSettings[ii];
5488 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5489 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5490 ioc->spi_data.nvram[ii] = data;
5491 }
5492 }
5493
5494 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5495 }
5496 }
5497
5498 /* Update Adapter limits with those from NVRAM
5499 * Comment: Don't need to do this. Target performance
5500 * parameters will never exceed the adapters limits.
5501 */
5502
5503 return rc;
5504}
5505
5506/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005507/**
5508 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 * @ioc: Pointer to a Adapter Strucutre
5510 * @portnum: IOC port number
5511 *
5512 * Return: -EFAULT if read of config page header fails
5513 * or 0 if success.
5514 */
5515static int
5516mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5517{
5518 CONFIGPARMS cfg;
5519 ConfigPageHeader_t header;
5520
5521 /* Read the SCSI Device Page 1 header
5522 */
5523 header.PageVersion = 0;
5524 header.PageLength = 0;
5525 header.PageNumber = 1;
5526 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005527 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528 cfg.physAddr = -1;
5529 cfg.pageAddr = portnum;
5530 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5531 cfg.dir = 0;
5532 cfg.timeout = 0;
5533 if (mpt_config(ioc, &cfg) != 0)
5534 return -EFAULT;
5535
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005536 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5537 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538
5539 header.PageVersion = 0;
5540 header.PageLength = 0;
5541 header.PageNumber = 0;
5542 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5543 if (mpt_config(ioc, &cfg) != 0)
5544 return -EFAULT;
5545
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005546 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5547 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005548
Prakash, Sathya436ace72007-07-24 15:42:08 +05305549 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5551
Prakash, Sathya436ace72007-07-24 15:42:08 +05305552 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5554 return 0;
5555}
5556
Eric Mooreb506ade2007-01-29 09:45:37 -07005557/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005558 * mpt_inactive_raid_list_free - This clears this link list.
5559 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005560 **/
5561static void
5562mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5563{
5564 struct inactive_raid_component_info *component_info, *pNext;
5565
5566 if (list_empty(&ioc->raid_data.inactive_list))
5567 return;
5568
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005569 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005570 list_for_each_entry_safe(component_info, pNext,
5571 &ioc->raid_data.inactive_list, list) {
5572 list_del(&component_info->list);
5573 kfree(component_info);
5574 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005575 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005576}
5577
5578/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005579 * 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 -07005580 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005581 * @ioc : pointer to per adapter structure
5582 * @channel : volume channel
5583 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005584 **/
5585static void
5586mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5587{
5588 CONFIGPARMS cfg;
5589 ConfigPageHeader_t hdr;
5590 dma_addr_t dma_handle;
5591 pRaidVolumePage0_t buffer = NULL;
5592 int i;
5593 RaidPhysDiskPage0_t phys_disk;
5594 struct inactive_raid_component_info *component_info;
5595 int handle_inactive_volumes;
5596
5597 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5598 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5599 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5600 cfg.pageAddr = (channel << 8) + id;
5601 cfg.cfghdr.hdr = &hdr;
5602 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5603
5604 if (mpt_config(ioc, &cfg) != 0)
5605 goto out;
5606
5607 if (!hdr.PageLength)
5608 goto out;
5609
5610 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5611 &dma_handle);
5612
5613 if (!buffer)
5614 goto out;
5615
5616 cfg.physAddr = dma_handle;
5617 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5618
5619 if (mpt_config(ioc, &cfg) != 0)
5620 goto out;
5621
5622 if (!buffer->NumPhysDisks)
5623 goto out;
5624
5625 handle_inactive_volumes =
5626 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5627 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5628 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5629 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5630
5631 if (!handle_inactive_volumes)
5632 goto out;
5633
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005634 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005635 for (i = 0; i < buffer->NumPhysDisks; i++) {
5636 if(mpt_raid_phys_disk_pg0(ioc,
5637 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5638 continue;
5639
5640 if ((component_info = kmalloc(sizeof (*component_info),
5641 GFP_KERNEL)) == NULL)
5642 continue;
5643
5644 component_info->volumeID = id;
5645 component_info->volumeBus = channel;
5646 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5647 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5648 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5649 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5650
5651 list_add_tail(&component_info->list,
5652 &ioc->raid_data.inactive_list);
5653 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005654 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005655
5656 out:
5657 if (buffer)
5658 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5659 dma_handle);
5660}
5661
5662/**
5663 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5664 * @ioc: Pointer to a Adapter Structure
5665 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5666 * @phys_disk: requested payload data returned
5667 *
5668 * Return:
5669 * 0 on success
5670 * -EFAULT if read of config page header fails or data pointer not NULL
5671 * -ENOMEM if pci_alloc failed
5672 **/
5673int
Kashyap, Desai2f187862009-05-29 16:52:37 +05305674mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
5675 RaidPhysDiskPage0_t *phys_disk)
Eric Mooreb506ade2007-01-29 09:45:37 -07005676{
Kashyap, Desai2f187862009-05-29 16:52:37 +05305677 CONFIGPARMS cfg;
5678 ConfigPageHeader_t hdr;
Eric Mooreb506ade2007-01-29 09:45:37 -07005679 dma_addr_t dma_handle;
5680 pRaidPhysDiskPage0_t buffer = NULL;
5681 int rc;
5682
5683 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5684 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
Kashyap, Desai2f187862009-05-29 16:52:37 +05305685 memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
Eric Mooreb506ade2007-01-29 09:45:37 -07005686
Kashyap, Desai2f187862009-05-29 16:52:37 +05305687 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
Eric Mooreb506ade2007-01-29 09:45:37 -07005688 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5689 cfg.cfghdr.hdr = &hdr;
5690 cfg.physAddr = -1;
5691 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5692
5693 if (mpt_config(ioc, &cfg) != 0) {
5694 rc = -EFAULT;
5695 goto out;
5696 }
5697
5698 if (!hdr.PageLength) {
5699 rc = -EFAULT;
5700 goto out;
5701 }
5702
5703 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5704 &dma_handle);
5705
5706 if (!buffer) {
5707 rc = -ENOMEM;
5708 goto out;
5709 }
5710
5711 cfg.physAddr = dma_handle;
5712 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5713 cfg.pageAddr = phys_disk_num;
5714
5715 if (mpt_config(ioc, &cfg) != 0) {
5716 rc = -EFAULT;
5717 goto out;
5718 }
5719
5720 rc = 0;
5721 memcpy(phys_disk, buffer, sizeof(*buffer));
5722 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5723
5724 out:
5725
5726 if (buffer)
5727 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5728 dma_handle);
5729
5730 return rc;
5731}
5732
Linus Torvalds1da177e2005-04-16 15:20:36 -07005733/**
Kashyap, Desaia7938b02009-05-29 16:53:56 +05305734 * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
5735 * @ioc: Pointer to a Adapter Structure
5736 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5737 *
5738 * Return:
5739 * returns number paths
5740 **/
5741int
5742mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
5743{
5744 CONFIGPARMS cfg;
5745 ConfigPageHeader_t hdr;
5746 dma_addr_t dma_handle;
5747 pRaidPhysDiskPage1_t buffer = NULL;
5748 int rc;
5749
5750 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5751 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5752
5753 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5754 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5755 hdr.PageNumber = 1;
5756 cfg.cfghdr.hdr = &hdr;
5757 cfg.physAddr = -1;
5758 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5759
5760 if (mpt_config(ioc, &cfg) != 0) {
5761 rc = 0;
5762 goto out;
5763 }
5764
5765 if (!hdr.PageLength) {
5766 rc = 0;
5767 goto out;
5768 }
5769
5770 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5771 &dma_handle);
5772
5773 if (!buffer) {
5774 rc = 0;
5775 goto out;
5776 }
5777
5778 cfg.physAddr = dma_handle;
5779 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5780 cfg.pageAddr = phys_disk_num;
5781
5782 if (mpt_config(ioc, &cfg) != 0) {
5783 rc = 0;
5784 goto out;
5785 }
5786
5787 rc = buffer->NumPhysDiskPaths;
5788 out:
5789
5790 if (buffer)
5791 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5792 dma_handle);
5793
5794 return rc;
5795}
5796EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
5797
5798/**
5799 * mpt_raid_phys_disk_pg1 - returns phys disk page 1
5800 * @ioc: Pointer to a Adapter Structure
5801 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5802 * @phys_disk: requested payload data returned
5803 *
5804 * Return:
5805 * 0 on success
5806 * -EFAULT if read of config page header fails or data pointer not NULL
5807 * -ENOMEM if pci_alloc failed
5808 **/
5809int
5810mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
5811 RaidPhysDiskPage1_t *phys_disk)
5812{
5813 CONFIGPARMS cfg;
5814 ConfigPageHeader_t hdr;
5815 dma_addr_t dma_handle;
5816 pRaidPhysDiskPage1_t buffer = NULL;
5817 int rc;
5818 int i;
5819 __le64 sas_address;
5820
5821 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5822 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5823 rc = 0;
5824
5825 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5826 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5827 hdr.PageNumber = 1;
5828 cfg.cfghdr.hdr = &hdr;
5829 cfg.physAddr = -1;
5830 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5831
5832 if (mpt_config(ioc, &cfg) != 0) {
5833 rc = -EFAULT;
5834 goto out;
5835 }
5836
5837 if (!hdr.PageLength) {
5838 rc = -EFAULT;
5839 goto out;
5840 }
5841
5842 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5843 &dma_handle);
5844
5845 if (!buffer) {
5846 rc = -ENOMEM;
5847 goto out;
5848 }
5849
5850 cfg.physAddr = dma_handle;
5851 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5852 cfg.pageAddr = phys_disk_num;
5853
5854 if (mpt_config(ioc, &cfg) != 0) {
5855 rc = -EFAULT;
5856 goto out;
5857 }
5858
5859 phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
5860 phys_disk->PhysDiskNum = phys_disk_num;
5861 for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
5862 phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
5863 phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
5864 phys_disk->Path[i].OwnerIdentifier =
5865 buffer->Path[i].OwnerIdentifier;
5866 phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
5867 memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
5868 sas_address = le64_to_cpu(sas_address);
5869 memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
5870 memcpy(&sas_address,
5871 &buffer->Path[i].OwnerWWID, sizeof(__le64));
5872 sas_address = le64_to_cpu(sas_address);
5873 memcpy(&phys_disk->Path[i].OwnerWWID,
5874 &sas_address, sizeof(__le64));
5875 }
5876
5877 out:
5878
5879 if (buffer)
5880 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5881 dma_handle);
5882
5883 return rc;
5884}
5885EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
5886
5887
5888/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5890 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891 *
5892 * Return:
5893 * 0 on success
5894 * -EFAULT if read of config page header fails or data pointer not NULL
5895 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005896 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005897int
5898mpt_findImVolumes(MPT_ADAPTER *ioc)
5899{
5900 IOCPage2_t *pIoc2;
5901 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902 dma_addr_t ioc2_dma;
5903 CONFIGPARMS cfg;
5904 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005905 int rc = 0;
5906 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005907 int i;
5908
5909 if (!ioc->ir_firmware)
5910 return 0;
5911
5912 /* Free the old page
5913 */
5914 kfree(ioc->raid_data.pIocPg2);
5915 ioc->raid_data.pIocPg2 = NULL;
5916 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005917
5918 /* Read IOCP2 header then the page.
5919 */
5920 header.PageVersion = 0;
5921 header.PageLength = 0;
5922 header.PageNumber = 2;
5923 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005924 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005925 cfg.physAddr = -1;
5926 cfg.pageAddr = 0;
5927 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5928 cfg.dir = 0;
5929 cfg.timeout = 0;
5930 if (mpt_config(ioc, &cfg) != 0)
5931 return -EFAULT;
5932
5933 if (header.PageLength == 0)
5934 return -EFAULT;
5935
5936 iocpage2sz = header.PageLength * 4;
5937 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5938 if (!pIoc2)
5939 return -ENOMEM;
5940
5941 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5942 cfg.physAddr = ioc2_dma;
5943 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005944 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005945
Eric Mooreb506ade2007-01-29 09:45:37 -07005946 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5947 if (!mem)
5948 goto out;
5949
Linus Torvalds1da177e2005-04-16 15:20:36 -07005950 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005951 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005952
Eric Mooreb506ade2007-01-29 09:45:37 -07005953 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005954
Eric Mooreb506ade2007-01-29 09:45:37 -07005955 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5956 mpt_inactive_raid_volumes(ioc,
5957 pIoc2->RaidVolume[i].VolumeBus,
5958 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959
Eric Mooreb506ade2007-01-29 09:45:37 -07005960 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005961 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5962
5963 return rc;
5964}
5965
Moore, Ericc972c702006-03-14 09:14:06 -07005966static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5968{
5969 IOCPage3_t *pIoc3;
5970 u8 *mem;
5971 CONFIGPARMS cfg;
5972 ConfigPageHeader_t header;
5973 dma_addr_t ioc3_dma;
5974 int iocpage3sz = 0;
5975
5976 /* Free the old page
5977 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005978 kfree(ioc->raid_data.pIocPg3);
5979 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980
5981 /* There is at least one physical disk.
5982 * Read and save IOC Page 3
5983 */
5984 header.PageVersion = 0;
5985 header.PageLength = 0;
5986 header.PageNumber = 3;
5987 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005988 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005989 cfg.physAddr = -1;
5990 cfg.pageAddr = 0;
5991 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5992 cfg.dir = 0;
5993 cfg.timeout = 0;
5994 if (mpt_config(ioc, &cfg) != 0)
5995 return 0;
5996
5997 if (header.PageLength == 0)
5998 return 0;
5999
6000 /* Read Header good, alloc memory
6001 */
6002 iocpage3sz = header.PageLength * 4;
6003 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
6004 if (!pIoc3)
6005 return 0;
6006
6007 /* Read the Page and save the data
6008 * into malloc'd memory.
6009 */
6010 cfg.physAddr = ioc3_dma;
6011 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6012 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07006013 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006014 if (mem) {
6015 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006016 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006017 }
6018 }
6019
6020 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
6021
6022 return 0;
6023}
6024
6025static void
6026mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
6027{
6028 IOCPage4_t *pIoc4;
6029 CONFIGPARMS cfg;
6030 ConfigPageHeader_t header;
6031 dma_addr_t ioc4_dma;
6032 int iocpage4sz;
6033
6034 /* Read and save IOC Page 4
6035 */
6036 header.PageVersion = 0;
6037 header.PageLength = 0;
6038 header.PageNumber = 4;
6039 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006040 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041 cfg.physAddr = -1;
6042 cfg.pageAddr = 0;
6043 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6044 cfg.dir = 0;
6045 cfg.timeout = 0;
6046 if (mpt_config(ioc, &cfg) != 0)
6047 return;
6048
6049 if (header.PageLength == 0)
6050 return;
6051
6052 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
6053 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
6054 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
6055 if (!pIoc4)
6056 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06006057 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006058 } else {
6059 ioc4_dma = ioc->spi_data.IocPg4_dma;
6060 iocpage4sz = ioc->spi_data.IocPg4Sz;
6061 }
6062
6063 /* Read the Page into dma memory.
6064 */
6065 cfg.physAddr = ioc4_dma;
6066 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6067 if (mpt_config(ioc, &cfg) == 0) {
6068 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
6069 ioc->spi_data.IocPg4_dma = ioc4_dma;
6070 ioc->spi_data.IocPg4Sz = iocpage4sz;
6071 } else {
6072 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
6073 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06006074 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006075 }
6076}
6077
6078static void
6079mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
6080{
6081 IOCPage1_t *pIoc1;
6082 CONFIGPARMS cfg;
6083 ConfigPageHeader_t header;
6084 dma_addr_t ioc1_dma;
6085 int iocpage1sz = 0;
6086 u32 tmp;
6087
6088 /* Check the Coalescing Timeout in IOC Page 1
6089 */
6090 header.PageVersion = 0;
6091 header.PageLength = 0;
6092 header.PageNumber = 1;
6093 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006094 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006095 cfg.physAddr = -1;
6096 cfg.pageAddr = 0;
6097 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6098 cfg.dir = 0;
6099 cfg.timeout = 0;
6100 if (mpt_config(ioc, &cfg) != 0)
6101 return;
6102
6103 if (header.PageLength == 0)
6104 return;
6105
6106 /* Read Header good, alloc memory
6107 */
6108 iocpage1sz = header.PageLength * 4;
6109 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
6110 if (!pIoc1)
6111 return;
6112
6113 /* Read the Page and check coalescing timeout
6114 */
6115 cfg.physAddr = ioc1_dma;
6116 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6117 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306118
Linus Torvalds1da177e2005-04-16 15:20:36 -07006119 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
6120 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
6121 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
6122
Prakash, Sathya436ace72007-07-24 15:42:08 +05306123 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006124 ioc->name, tmp));
6125
6126 if (tmp > MPT_COALESCING_TIMEOUT) {
6127 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
6128
6129 /* Write NVRAM and current
6130 */
6131 cfg.dir = 1;
6132 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
6133 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306134 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135 ioc->name, MPT_COALESCING_TIMEOUT));
6136
6137 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
6138 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306139 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6140 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141 ioc->name, MPT_COALESCING_TIMEOUT));
6142 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306143 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6144 "Reset NVRAM Coalescing Timeout Failed\n",
6145 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006146 }
6147
6148 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306149 dprintk(ioc, printk(MYIOC_s_WARN_FMT
6150 "Reset of Current Coalescing Timeout Failed!\n",
6151 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006152 }
6153 }
6154
6155 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306156 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006157 }
6158 }
6159
6160 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
6161
6162 return;
6163}
6164
Prakash, Sathyaedb90682007-07-17 14:39:14 +05306165static void
6166mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
6167{
6168 CONFIGPARMS cfg;
6169 ConfigPageHeader_t hdr;
6170 dma_addr_t buf_dma;
6171 ManufacturingPage0_t *pbuf = NULL;
6172
6173 memset(&cfg, 0 , sizeof(CONFIGPARMS));
6174 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
6175
6176 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
6177 cfg.cfghdr.hdr = &hdr;
6178 cfg.physAddr = -1;
6179 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6180 cfg.timeout = 10;
6181
6182 if (mpt_config(ioc, &cfg) != 0)
6183 goto out;
6184
6185 if (!cfg.cfghdr.hdr->PageLength)
6186 goto out;
6187
6188 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6189 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
6190 if (!pbuf)
6191 goto out;
6192
6193 cfg.physAddr = buf_dma;
6194
6195 if (mpt_config(ioc, &cfg) != 0)
6196 goto out;
6197
6198 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
6199 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
6200 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
6201
6202 out:
6203
6204 if (pbuf)
6205 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
6206}
6207
Linus Torvalds1da177e2005-04-16 15:20:36 -07006208/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006209/**
6210 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211 * @ioc: Pointer to MPT_ADAPTER structure
6212 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05306213 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07006214 */
6215static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05306216SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217{
Kashyap, Desaifd761752009-05-29 16:39:06 +05306218 EventNotification_t evn;
6219 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006220
Kashyap, Desaifd761752009-05-29 16:39:06 +05306221 memset(&evn, 0, sizeof(EventNotification_t));
6222 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223
Kashyap, Desaifd761752009-05-29 16:39:06 +05306224 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
6225 evn.Switch = EvSwitch;
6226 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006227
Kashyap, Desaifd761752009-05-29 16:39:06 +05306228 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6229 "Sending EventNotification (%d) request %p\n",
6230 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006231
Kashyap, Desaifd761752009-05-29 16:39:06 +05306232 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6233 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6234 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006235}
6236
6237/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6238/**
6239 * SendEventAck - Send EventAck request to MPT adapter.
6240 * @ioc: Pointer to MPT_ADAPTER structure
6241 * @evnp: Pointer to original EventNotification request
6242 */
6243static int
6244SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6245{
6246 EventAck_t *pAck;
6247
6248 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306249 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306250 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251 return -1;
6252 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006253
Prakash, Sathya436ace72007-07-24 15:42:08 +05306254 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006255
6256 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6257 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006258 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006259 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006260 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006261 pAck->Event = evnp->Event;
6262 pAck->EventContext = evnp->EventContext;
6263
6264 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6265
6266 return 0;
6267}
6268
6269/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6270/**
6271 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006272 * @ioc: Pointer to an adapter structure
6273 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274 * action, page address, direction, physical address
6275 * and pointer to a configuration page header
6276 * Page header is updated.
6277 *
6278 * Returns 0 for success
6279 * -EPERM if not allowed due to ISR context
6280 * -EAGAIN if no msg frames currently available
6281 * -EFAULT for non-successful reply or no reply (timeout)
6282 */
6283int
6284mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6285{
6286 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306287 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006288 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006289 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306290 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006291 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306292 long timeout;
6293 int ret;
6294 u8 page_type = 0, extend_page;
6295 unsigned long timeleft;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306296 unsigned long flags;
6297 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306298 u8 issue_hard_reset = 0;
6299 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006300
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006301 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006302 * to be in ISR context, because that is fatal!
6303 */
6304 in_isr = in_interrupt();
6305 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306306 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006307 ioc->name));
6308 return -EPERM;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306309 }
6310
6311 /* don't send a config page during diag reset */
6312 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6313 if (ioc->ioc_reset_in_progress) {
6314 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6315 "%s: busy with host reset\n", ioc->name, __func__));
6316 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6317 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006318 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306319 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006320
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306321 /* don't send if no chance of success */
6322 if (!ioc->active ||
6323 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6324 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6325 "%s: ioc not operational, %d, %xh\n",
6326 ioc->name, __func__, ioc->active,
6327 mpt_GetIocState(ioc, 0)));
6328 return -EFAULT;
6329 }
6330
6331 retry_config:
6332 mutex_lock(&ioc->mptbase_cmds.mutex);
6333 /* init the internal cmd struct */
6334 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6335 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6336
Linus Torvalds1da177e2005-04-16 15:20:36 -07006337 /* Get and Populate a free Frame
6338 */
6339 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306340 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6341 "mpt_config: no msg frames!\n", ioc->name));
6342 ret = -EAGAIN;
6343 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006344 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306345
Linus Torvalds1da177e2005-04-16 15:20:36 -07006346 pReq = (Config_t *)mf;
6347 pReq->Action = pCfg->action;
6348 pReq->Reserved = 0;
6349 pReq->ChainOffset = 0;
6350 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006351
6352 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006353 pReq->ExtPageLength = 0;
6354 pReq->ExtPageType = 0;
6355 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006356
Linus Torvalds1da177e2005-04-16 15:20:36 -07006357 for (ii=0; ii < 8; ii++)
6358 pReq->Reserved2[ii] = 0;
6359
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006360 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6361 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6362 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6363 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6364
6365 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6366 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6367 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6368 pReq->ExtPageType = pExtHdr->ExtPageType;
6369 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6370
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306371 /* Page Length must be treated as a reserved field for the
6372 * extended header.
6373 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006374 pReq->Header.PageLength = 0;
6375 }
6376
Linus Torvalds1da177e2005-04-16 15:20:36 -07006377 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6378
6379 /* Add a SGE to the config request.
6380 */
6381 if (pCfg->dir)
6382 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6383 else
6384 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6385
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306386 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6387 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006388 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306389 page_type = pReq->ExtPageType;
6390 extend_page = 1;
6391 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006392 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306393 page_type = pReq->Header.PageType;
6394 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006395 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006396
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306397 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6398 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6399 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6400
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306401 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306402 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006403 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306404 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6405 timeout);
6406 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6407 ret = -ETIME;
6408 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6409 "Failed Sending Config request type 0x%x, page 0x%x,"
6410 " action %d, status %xh, time left %ld\n\n",
6411 ioc->name, page_type, pReq->Header.PageNumber,
6412 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6413 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6414 goto out;
6415 if (!timeleft)
6416 issue_hard_reset = 1;
6417 goto out;
6418 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006419
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306420 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6421 ret = -1;
6422 goto out;
6423 }
6424 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6425 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6426 if (ret == MPI_IOCSTATUS_SUCCESS) {
6427 if (extend_page) {
6428 pCfg->cfghdr.ehdr->ExtPageLength =
6429 le16_to_cpu(pReply->ExtPageLength);
6430 pCfg->cfghdr.ehdr->ExtPageType =
6431 pReply->ExtPageType;
6432 }
6433 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6434 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6435 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6436 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006437
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306438 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006439
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306440 if (retry_count)
6441 printk(MYIOC_s_INFO_FMT "Retry completed "
6442 "ret=0x%x timeleft=%ld\n",
6443 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006444
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306445 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6446 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006447
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306448out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006449
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306450 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6451 mutex_unlock(&ioc->mptbase_cmds.mutex);
6452 if (issue_hard_reset) {
6453 issue_hard_reset = 0;
Kei Tokunaga97009a22010-06-22 19:01:51 +09006454 printk(MYIOC_s_WARN_FMT
6455 "Issuing Reset from %s!!, doorbell=0x%08x\n",
6456 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaib3b97312010-03-18 19:14:51 +05306457 if (retry_count == 0) {
6458 if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0)
6459 retry_count++;
6460 } else
6461 mpt_HardResetHandler(ioc, CAN_SLEEP);
6462
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306463 mpt_free_msg_frame(ioc, mf);
6464 /* attempt one retry for a timed out command */
Kashyap, Desaib3b97312010-03-18 19:14:51 +05306465 if (retry_count < 2) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306466 printk(MYIOC_s_INFO_FMT
6467 "Attempting Retry Config request"
6468 " type 0x%x, page 0x%x,"
6469 " action %d\n", ioc->name, page_type,
6470 pCfg->cfghdr.hdr->PageNumber, pCfg->action);
6471 retry_count++;
6472 goto retry_config;
6473 }
6474 }
6475 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006476
Linus Torvalds1da177e2005-04-16 15:20:36 -07006477}
6478
6479/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006480/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006481 * mpt_ioc_reset - Base cleanup for hard reset
6482 * @ioc: Pointer to the adapter structure
6483 * @reset_phase: Indicates pre- or post-reset functionality
6484 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006485 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006486 */
6487static int
6488mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6489{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306490 switch (reset_phase) {
6491 case MPT_IOC_SETUP_RESET:
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306492 ioc->taskmgmt_quiesce_io = 1;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306493 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6494 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
6495 break;
6496 case MPT_IOC_PRE_RESET:
6497 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6498 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
6499 break;
6500 case MPT_IOC_POST_RESET:
6501 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6502 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
6503/* wake up mptbase_cmds */
6504 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6505 ioc->mptbase_cmds.status |=
6506 MPT_MGMT_STATUS_DID_IOCRESET;
6507 complete(&ioc->mptbase_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006508 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306509/* wake up taskmgmt_cmds */
6510 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
6511 ioc->taskmgmt_cmds.status |=
6512 MPT_MGMT_STATUS_DID_IOCRESET;
6513 complete(&ioc->taskmgmt_cmds.done);
6514 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306515 break;
6516 default:
6517 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006518 }
6519
6520 return 1; /* currently means nothing really */
6521}
6522
6523
6524#ifdef CONFIG_PROC_FS /* { */
6525/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6526/*
6527 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6528 */
6529/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006530/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006531 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6532 *
6533 * Returns 0 for success, non-zero for failure.
6534 */
6535static int
6536procmpt_create(void)
6537{
Linus Torvalds1da177e2005-04-16 15:20:36 -07006538 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6539 if (mpt_proc_root_dir == NULL)
6540 return -ENOTDIR;
6541
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006542 proc_create("summary", S_IRUGO, mpt_proc_root_dir, &mpt_summary_proc_fops);
6543 proc_create("version", S_IRUGO, mpt_proc_root_dir, &mpt_version_proc_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006544 return 0;
6545}
6546
6547/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006548/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006549 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6550 *
6551 * Returns 0 for success, non-zero for failure.
6552 */
6553static void
6554procmpt_destroy(void)
6555{
6556 remove_proc_entry("version", mpt_proc_root_dir);
6557 remove_proc_entry("summary", mpt_proc_root_dir);
6558 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6559}
6560
6561/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlap1f5cfe22010-08-14 13:05:50 -07006562/*
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006563 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006564 */
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006565static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan);
6566
6567static int mpt_summary_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006568{
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006569 MPT_ADAPTER *ioc = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006570
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006571 if (ioc) {
6572 seq_mpt_print_ioc_summary(ioc, m, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006573 } else {
6574 list_for_each_entry(ioc, &ioc_list, list) {
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006575 seq_mpt_print_ioc_summary(ioc, m, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006576 }
6577 }
6578
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006579 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006580}
6581
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006582static int mpt_summary_proc_open(struct inode *inode, struct file *file)
6583{
6584 return single_open(file, mpt_summary_proc_show, PDE(inode)->data);
6585}
6586
6587static const struct file_operations mpt_summary_proc_fops = {
6588 .owner = THIS_MODULE,
6589 .open = mpt_summary_proc_open,
6590 .read = seq_read,
6591 .llseek = seq_lseek,
6592 .release = single_release,
6593};
6594
6595static int mpt_version_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006596{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306597 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006598 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006599 char *drvname;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006600
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006601 seq_printf(m, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6602 seq_printf(m, " Fusion MPT base driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006603
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006604 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006605 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006606 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306607 if (MptCallbacks[cb_idx]) {
6608 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006609 case MPTSPI_DRIVER:
6610 if (!scsi++) drvname = "SPI host";
6611 break;
6612 case MPTFC_DRIVER:
6613 if (!fc++) drvname = "FC host";
6614 break;
6615 case MPTSAS_DRIVER:
6616 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006617 break;
6618 case MPTLAN_DRIVER:
6619 if (!lan++) drvname = "LAN";
6620 break;
6621 case MPTSTM_DRIVER:
6622 if (!targ++) drvname = "SCSI target";
6623 break;
6624 case MPTCTL_DRIVER:
6625 if (!ctl++) drvname = "ioctl";
6626 break;
6627 }
6628
6629 if (drvname)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006630 seq_printf(m, " Fusion MPT %s driver\n", drvname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006631 }
6632 }
6633
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006634 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006635}
6636
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006637static int mpt_version_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006638{
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006639 return single_open(file, mpt_version_proc_show, NULL);
6640}
6641
6642static const struct file_operations mpt_version_proc_fops = {
6643 .owner = THIS_MODULE,
6644 .open = mpt_version_proc_open,
6645 .read = seq_read,
6646 .llseek = seq_lseek,
6647 .release = single_release,
6648};
6649
6650static int mpt_iocinfo_proc_show(struct seq_file *m, void *v)
6651{
6652 MPT_ADAPTER *ioc = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006653 char expVer[32];
6654 int sz;
6655 int p;
6656
6657 mpt_get_fw_exp_ver(expVer, ioc);
6658
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006659 seq_printf(m, "%s:", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006660 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006661 seq_printf(m, " (f/w download boot flag set)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006662// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006663// seq_printf(m, " CONFIG_CHECKSUM_FAIL!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006664
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006665 seq_printf(m, "\n ProductID = 0x%04x (%s)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006666 ioc->facts.ProductID,
6667 ioc->prod_name);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006668 seq_printf(m, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006669 if (ioc->facts.FWImageSize)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006670 seq_printf(m, " (fw_size=%d)", ioc->facts.FWImageSize);
6671 seq_printf(m, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6672 seq_printf(m, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6673 seq_printf(m, " EventState = 0x%02x\n", ioc->facts.EventState);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006674
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006675 seq_printf(m, " CurrentHostMfaHighAddr = 0x%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006676 ioc->facts.CurrentHostMfaHighAddr);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006677 seq_printf(m, " CurrentSenseBufferHighAddr = 0x%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006678 ioc->facts.CurrentSenseBufferHighAddr);
6679
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006680 seq_printf(m, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6681 seq_printf(m, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006682
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006683 seq_printf(m, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006684 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6685 /*
6686 * Rounding UP to nearest 4-kB boundary here...
6687 */
6688 sz = (ioc->req_sz * ioc->req_depth) + 128;
6689 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006690 seq_printf(m, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006691 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006692 seq_printf(m, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006693 4*ioc->facts.RequestFrameSize,
6694 ioc->facts.GlobalCredits);
6695
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006696 seq_printf(m, " Frames @ 0x%p (Dma @ 0x%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006697 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6698 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006699 seq_printf(m, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006700 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006701 seq_printf(m, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006702 ioc->facts.CurReplyFrameSize,
6703 ioc->facts.ReplyQueueDepth);
6704
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006705 seq_printf(m, " MaxDevices = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006706 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006707 seq_printf(m, " MaxBuses = %d\n", ioc->facts.MaxBuses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006708
6709 /* per-port info */
6710 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006711 seq_printf(m, " PortNumber = %d (of %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006712 p+1,
6713 ioc->facts.NumberOfPorts);
6714 if (ioc->bus_type == FC) {
6715 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6716 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006717 seq_printf(m, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006718 a[5], a[4], a[3], a[2], a[1], a[0]);
6719 }
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006720 seq_printf(m, " WWN = %08X%08X:%08X%08X\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006721 ioc->fc_port_page0[p].WWNN.High,
6722 ioc->fc_port_page0[p].WWNN.Low,
6723 ioc->fc_port_page0[p].WWPN.High,
6724 ioc->fc_port_page0[p].WWPN.Low);
6725 }
6726 }
6727
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006728 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006729}
6730
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006731static int mpt_iocinfo_proc_open(struct inode *inode, struct file *file)
6732{
6733 return single_open(file, mpt_iocinfo_proc_show, PDE(inode)->data);
6734}
6735
6736static const struct file_operations mpt_iocinfo_proc_fops = {
6737 .owner = THIS_MODULE,
6738 .open = mpt_iocinfo_proc_open,
6739 .read = seq_read,
6740 .llseek = seq_lseek,
6741 .release = single_release,
6742};
Linus Torvalds1da177e2005-04-16 15:20:36 -07006743#endif /* CONFIG_PROC_FS } */
6744
6745/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6746static void
6747mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6748{
6749 buf[0] ='\0';
6750 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6751 sprintf(buf, " (Exp %02d%02d)",
6752 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6753 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6754
6755 /* insider hack! */
6756 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6757 strcat(buf, " [MDBG]");
6758 }
6759}
6760
6761/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6762/**
6763 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6764 * @ioc: Pointer to MPT_ADAPTER structure
6765 * @buffer: Pointer to buffer where IOC summary info should be written
6766 * @size: Pointer to number of bytes we wrote (set by this routine)
6767 * @len: Offset at which to start writing in buffer
6768 * @showlan: Display LAN stuff?
6769 *
6770 * This routine writes (english readable) ASCII text, which represents
6771 * a summary of IOC information, to a buffer.
6772 */
6773void
6774mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6775{
6776 char expVer[32];
6777 int y;
6778
6779 mpt_get_fw_exp_ver(expVer, ioc);
6780
6781 /*
6782 * Shorter summary of attached ioc's...
6783 */
6784 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6785 ioc->name,
6786 ioc->prod_name,
6787 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6788 ioc->facts.FWVersion.Word,
6789 expVer,
6790 ioc->facts.NumberOfPorts,
6791 ioc->req_depth);
6792
6793 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6794 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6795 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6796 a[5], a[4], a[3], a[2], a[1], a[0]);
6797 }
6798
Linus Torvalds1da177e2005-04-16 15:20:36 -07006799 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006800
6801 if (!ioc->active)
6802 y += sprintf(buffer+len+y, " (disabled)");
6803
6804 y += sprintf(buffer+len+y, "\n");
6805
6806 *size = y;
6807}
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006808
6809static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan)
6810{
6811 char expVer[32];
6812
6813 mpt_get_fw_exp_ver(expVer, ioc);
6814
6815 /*
6816 * Shorter summary of attached ioc's...
6817 */
6818 seq_printf(m, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6819 ioc->name,
6820 ioc->prod_name,
6821 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6822 ioc->facts.FWVersion.Word,
6823 expVer,
6824 ioc->facts.NumberOfPorts,
6825 ioc->req_depth);
6826
6827 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6828 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6829 seq_printf(m, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6830 a[5], a[4], a[3], a[2], a[1], a[0]);
6831 }
6832
6833 seq_printf(m, ", IRQ=%d", ioc->pci_irq);
6834
6835 if (!ioc->active)
6836 seq_printf(m, " (disabled)");
6837
6838 seq_putc(m, '\n');
6839}
6840
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306841/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006842 * mpt_set_taskmgmt_in_progress_flag - set flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306843 * @ioc: Pointer to MPT_ADAPTER structure
6844 *
6845 * Returns 0 for SUCCESS or -1 if FAILED.
6846 *
6847 * If -1 is return, then it was not possible to set the flags
6848 **/
6849int
6850mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6851{
6852 unsigned long flags;
6853 int retval;
6854
6855 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6856 if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
6857 (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
6858 retval = -1;
6859 goto out;
6860 }
6861 retval = 0;
6862 ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306863 ioc->taskmgmt_quiesce_io = 1;
6864 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306865 ioc->alt_ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306866 ioc->alt_ioc->taskmgmt_quiesce_io = 1;
6867 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306868 out:
6869 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6870 return retval;
6871}
6872EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
6873
6874/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006875 * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306876 * @ioc: Pointer to MPT_ADAPTER structure
6877 *
6878 **/
6879void
6880mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6881{
6882 unsigned long flags;
6883
6884 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6885 ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306886 ioc->taskmgmt_quiesce_io = 0;
6887 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306888 ioc->alt_ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306889 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
6890 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306891 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6892}
6893EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006894
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306895
6896/**
6897 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6898 * the kernel
6899 * @ioc: Pointer to MPT_ADAPTER structure
6900 *
6901 **/
6902void
6903mpt_halt_firmware(MPT_ADAPTER *ioc)
6904{
6905 u32 ioc_raw_state;
6906
6907 ioc_raw_state = mpt_GetIocState(ioc, 0);
6908
6909 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6910 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6911 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6912 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6913 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6914 } else {
6915 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6916 panic("%s: Firmware is halted due to command timeout\n",
6917 ioc->name);
6918 }
6919}
6920EXPORT_SYMBOL(mpt_halt_firmware);
6921
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306922/**
6923 * mpt_SoftResetHandler - Issues a less expensive reset
6924 * @ioc: Pointer to MPT_ADAPTER structure
6925 * @sleepFlag: Indicates if sleep or schedule must be called.
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306926 *
6927 * Returns 0 for SUCCESS or -1 if FAILED.
6928 *
6929 * Message Unit Reset - instructs the IOC to reset the Reply Post and
6930 * Free FIFO's. All the Message Frames on Reply Free FIFO are discarded.
6931 * All posted buffers are freed, and event notification is turned off.
6932 * IOC doesnt reply to any outstanding request. This will transfer IOC
6933 * to READY state.
6934 **/
6935int
6936mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6937{
6938 int rc;
6939 int ii;
6940 u8 cb_idx;
6941 unsigned long flags;
6942 u32 ioc_state;
6943 unsigned long time_count;
6944
6945 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n",
6946 ioc->name));
6947
6948 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
6949
6950 if (mpt_fwfault_debug)
6951 mpt_halt_firmware(ioc);
6952
6953 if (ioc_state == MPI_IOC_STATE_FAULT ||
6954 ioc_state == MPI_IOC_STATE_RESET) {
6955 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6956 "skipping, either in FAULT or RESET state!\n", ioc->name));
6957 return -1;
6958 }
6959
6960 if (ioc->bus_type == FC) {
6961 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6962 "skipping, because the bus type is FC!\n", ioc->name));
6963 return -1;
6964 }
6965
6966 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6967 if (ioc->ioc_reset_in_progress) {
6968 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6969 return -1;
6970 }
6971 ioc->ioc_reset_in_progress = 1;
6972 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6973
6974 rc = -1;
6975
6976 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6977 if (MptResetHandlers[cb_idx])
6978 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
6979 }
6980
6981 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6982 if (ioc->taskmgmt_in_progress) {
Kashyap, Desaib9a0f872010-06-17 14:42:39 +05306983 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306984 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6985 return -1;
6986 }
6987 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6988 /* Disable reply interrupts (also blocks FreeQ) */
6989 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
6990 ioc->active = 0;
6991 time_count = jiffies;
6992
6993 rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
6994
6995 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6996 if (MptResetHandlers[cb_idx])
6997 mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
6998 }
6999
7000 if (rc)
7001 goto out;
7002
7003 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
7004 if (ioc_state != MPI_IOC_STATE_READY)
7005 goto out;
7006
7007 for (ii = 0; ii < 5; ii++) {
7008 /* Get IOC facts! Allow 5 retries */
7009 rc = GetIocFacts(ioc, sleepFlag,
7010 MPT_HOSTEVENT_IOC_RECOVER);
7011 if (rc == 0)
7012 break;
7013 if (sleepFlag == CAN_SLEEP)
7014 msleep(100);
7015 else
7016 mdelay(100);
7017 }
7018 if (ii == 5)
7019 goto out;
7020
7021 rc = PrimeIocFifos(ioc);
7022 if (rc != 0)
7023 goto out;
7024
7025 rc = SendIocInit(ioc, sleepFlag);
7026 if (rc != 0)
7027 goto out;
7028
7029 rc = SendEventNotification(ioc, 1, sleepFlag);
7030 if (rc != 0)
7031 goto out;
7032
7033 if (ioc->hard_resets < -1)
7034 ioc->hard_resets++;
7035
7036 /*
7037 * At this point, we know soft reset succeeded.
7038 */
7039
7040 ioc->active = 1;
7041 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
7042
7043 out:
7044 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7045 ioc->ioc_reset_in_progress = 0;
7046 ioc->taskmgmt_quiesce_io = 0;
7047 ioc->taskmgmt_in_progress = 0;
7048 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7049
7050 if (ioc->active) { /* otherwise, hard reset coming */
7051 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7052 if (MptResetHandlers[cb_idx])
7053 mpt_signal_reset(cb_idx, ioc,
7054 MPT_IOC_POST_RESET);
7055 }
7056 }
7057
7058 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7059 "SoftResetHandler: completed (%d seconds): %s\n",
7060 ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,
7061 ((rc == 0) ? "SUCCESS" : "FAILED")));
7062
7063 return rc;
7064}
7065
7066/**
7067 * mpt_Soft_Hard_ResetHandler - Try less expensive reset
7068 * @ioc: Pointer to MPT_ADAPTER structure
7069 * @sleepFlag: Indicates if sleep or schedule must be called.
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05307070 *
7071 * Returns 0 for SUCCESS or -1 if FAILED.
7072 * Try for softreset first, only if it fails go for expensive
7073 * HardReset.
7074 **/
7075int
7076mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag) {
7077 int ret = -1;
7078
7079 ret = mpt_SoftResetHandler(ioc, sleepFlag);
7080 if (ret == 0)
7081 return ret;
7082 ret = mpt_HardResetHandler(ioc, sleepFlag);
7083 return ret;
7084}
7085EXPORT_SYMBOL(mpt_Soft_Hard_ResetHandler);
7086
Linus Torvalds1da177e2005-04-16 15:20:36 -07007087/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7088/*
7089 * Reset Handling
7090 */
7091/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7092/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007093 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07007094 * @ioc: Pointer to MPT_ADAPTER structure
7095 * @sleepFlag: Indicates if sleep or schedule must be called.
7096 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007097 * Issues SCSI Task Management call based on input arg values.
7098 * If TaskMgmt fails, returns associated SCSI request.
7099 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07007100 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
7101 * or a non-interrupt thread. In the former, must not call schedule().
7102 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007103 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07007104 * FW reload/initialization failed.
7105 *
7106 * Returns 0 for SUCCESS or -1 if FAILED.
7107 */
7108int
7109mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
7110{
Kashyap, Desaid1306912009-08-05 12:53:51 +05307111 int rc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307112 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007113 unsigned long flags;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307114 unsigned long time_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007115
Prakash, Sathya436ace72007-07-24 15:42:08 +05307116 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007117#ifdef MFCNT
7118 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
7119 printk("MF count 0x%x !\n", ioc->mfcnt);
7120#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05307121 if (mpt_fwfault_debug)
7122 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007123
7124 /* Reset the adapter. Prevent more than 1 call to
7125 * mpt_do_ioc_recovery at any instant in time.
7126 */
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307127 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7128 if (ioc->ioc_reset_in_progress) {
7129 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007130 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007131 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307132 ioc->ioc_reset_in_progress = 1;
7133 if (ioc->alt_ioc)
7134 ioc->alt_ioc->ioc_reset_in_progress = 1;
7135 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007136
Linus Torvalds1da177e2005-04-16 15:20:36 -07007137
7138 /* The SCSI driver needs to adjust timeouts on all current
7139 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02007140 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007141 * For all other protocol drivers, this is a no-op.
7142 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05307143 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7144 if (MptResetHandlers[cb_idx]) {
7145 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
7146 if (ioc->alt_ioc)
7147 mpt_signal_reset(cb_idx, ioc->alt_ioc,
7148 MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007149 }
7150 }
7151
Kashyap, Desai2f187862009-05-29 16:52:37 +05307152 time_count = jiffies;
7153 rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
7154 if (rc != 0) {
7155 printk(KERN_WARNING MYNAM
Kei Tokunaga97009a22010-06-22 19:01:51 +09007156 ": WARNING - (%d) Cannot recover %s, doorbell=0x%08x\n",
7157 rc, ioc->name, mpt_GetIocState(ioc, 0));
Kashyap, Desai2f187862009-05-29 16:52:37 +05307158 } else {
7159 if (ioc->hard_resets < -1)
7160 ioc->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007161 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007162
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307163 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7164 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307165 ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307166 ioc->taskmgmt_in_progress = 0;
7167 if (ioc->alt_ioc) {
7168 ioc->alt_ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307169 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307170 ioc->alt_ioc->taskmgmt_in_progress = 0;
7171 }
7172 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007173
Kashyap, Desaid1306912009-08-05 12:53:51 +05307174 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7175 if (MptResetHandlers[cb_idx]) {
7176 mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
7177 if (ioc->alt_ioc)
7178 mpt_signal_reset(cb_idx,
7179 ioc->alt_ioc, MPT_IOC_POST_RESET);
7180 }
7181 }
7182
Kashyap, Desai2f187862009-05-29 16:52:37 +05307183 dtmprintk(ioc,
7184 printk(MYIOC_s_DEBUG_FMT
7185 "HardResetHandler: completed (%d seconds): %s\n", ioc->name,
7186 jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?
7187 "SUCCESS" : "FAILED")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007188
7189 return rc;
7190}
7191
Kashyap, Desai2f187862009-05-29 16:52:37 +05307192#ifdef CONFIG_FUSION_LOGGING
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007193static void
Kashyap, Desai2f187862009-05-29 16:52:37 +05307194mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007195{
Eric Moore509e5e52006-04-26 13:22:37 -06007196 char *ds = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307197 u32 evData0;
7198 int ii;
7199 u8 event;
7200 char *evStr = ioc->evStr;
7201
7202 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7203 evData0 = le32_to_cpu(pEventReply->Data[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007204
7205 switch(event) {
7206 case MPI_EVENT_NONE:
7207 ds = "None";
7208 break;
7209 case MPI_EVENT_LOG_DATA:
7210 ds = "Log Data";
7211 break;
7212 case MPI_EVENT_STATE_CHANGE:
7213 ds = "State Change";
7214 break;
7215 case MPI_EVENT_UNIT_ATTENTION:
7216 ds = "Unit Attention";
7217 break;
7218 case MPI_EVENT_IOC_BUS_RESET:
7219 ds = "IOC Bus Reset";
7220 break;
7221 case MPI_EVENT_EXT_BUS_RESET:
7222 ds = "External Bus Reset";
7223 break;
7224 case MPI_EVENT_RESCAN:
7225 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007226 break;
7227 case MPI_EVENT_LINK_STATUS_CHANGE:
7228 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
7229 ds = "Link Status(FAILURE) Change";
7230 else
7231 ds = "Link Status(ACTIVE) Change";
7232 break;
7233 case MPI_EVENT_LOOP_STATE_CHANGE:
7234 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
7235 ds = "Loop State(LIP) Change";
7236 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Kashyap, Desai2f187862009-05-29 16:52:37 +05307237 ds = "Loop State(LPE) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007238 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05307239 ds = "Loop State(LPB) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007240 break;
7241 case MPI_EVENT_LOGOUT:
7242 ds = "Logout";
7243 break;
7244 case MPI_EVENT_EVENT_CHANGE:
7245 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06007246 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007247 else
Eric Moore4f766dc2006-07-11 17:24:07 -06007248 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007249 break;
7250 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007251 {
7252 u8 ReasonCode = (u8)(evData0 >> 16);
7253 switch (ReasonCode) {
7254 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
7255 ds = "Integrated Raid: Volume Created";
7256 break;
7257 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
7258 ds = "Integrated Raid: Volume Deleted";
7259 break;
7260 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
7261 ds = "Integrated Raid: Volume Settings Changed";
7262 break;
7263 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
7264 ds = "Integrated Raid: Volume Status Changed";
7265 break;
7266 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
7267 ds = "Integrated Raid: Volume Physdisk Changed";
7268 break;
7269 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
7270 ds = "Integrated Raid: Physdisk Created";
7271 break;
7272 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
7273 ds = "Integrated Raid: Physdisk Deleted";
7274 break;
7275 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
7276 ds = "Integrated Raid: Physdisk Settings Changed";
7277 break;
7278 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
7279 ds = "Integrated Raid: Physdisk Status Changed";
7280 break;
7281 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
7282 ds = "Integrated Raid: Domain Validation Needed";
7283 break;
7284 case MPI_EVENT_RAID_RC_SMART_DATA :
7285 ds = "Integrated Raid; Smart Data";
7286 break;
7287 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
7288 ds = "Integrated Raid: Replace Action Started";
7289 break;
7290 default:
7291 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007292 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007293 }
7294 break;
7295 }
7296 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
7297 ds = "SCSI Device Status Change";
7298 break;
7299 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
7300 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007301 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007302 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007303 u8 ReasonCode = (u8)(evData0 >> 16);
7304 switch (ReasonCode) {
7305 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007306 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007307 "SAS Device Status Change: Added: "
7308 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007309 break;
7310 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06007311 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007312 "SAS Device Status Change: Deleted: "
7313 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007314 break;
7315 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06007316 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007317 "SAS Device Status Change: SMART Data: "
7318 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007319 break;
7320 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007321 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007322 "SAS Device Status Change: No Persistancy: "
7323 "id=%d channel=%d", id, channel);
7324 break;
7325 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
7326 snprintf(evStr, EVENT_DESCR_STR_SZ,
7327 "SAS Device Status Change: Unsupported Device "
7328 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007329 break;
7330 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
7331 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007332 "SAS Device Status Change: Internal Device "
7333 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007334 break;
7335 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
7336 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007337 "SAS Device Status Change: Internal Task "
7338 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007339 break;
7340 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
7341 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007342 "SAS Device Status Change: Internal Abort "
7343 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007344 break;
7345 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
7346 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007347 "SAS Device Status Change: Internal Clear "
7348 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007349 break;
7350 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
7351 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007352 "SAS Device Status Change: Internal Query "
7353 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007354 break;
7355 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007356 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007357 "SAS Device Status Change: Unknown: "
7358 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06007359 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007360 }
7361 break;
7362 }
7363 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
7364 ds = "Bus Timer Expired";
7365 break;
7366 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07007367 {
7368 u16 curr_depth = (u16)(evData0 >> 16);
7369 u8 channel = (u8)(evData0 >> 8);
7370 u8 id = (u8)(evData0);
7371
7372 snprintf(evStr, EVENT_DESCR_STR_SZ,
7373 "Queue Full: channel=%d id=%d depth=%d",
7374 channel, id, curr_depth);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007375 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07007376 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007377 case MPI_EVENT_SAS_SES:
7378 ds = "SAS SES Event";
7379 break;
7380 case MPI_EVENT_PERSISTENT_TABLE_FULL:
7381 ds = "Persistent Table Full";
7382 break;
7383 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07007384 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007385 u8 LinkRates = (u8)(evData0 >> 8);
7386 u8 PhyNumber = (u8)(evData0);
7387 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
7388 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
7389 switch (LinkRates) {
7390 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06007391 snprintf(evStr, EVENT_DESCR_STR_SZ,
7392 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007393 " Rate Unknown",PhyNumber);
7394 break;
7395 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06007396 snprintf(evStr, EVENT_DESCR_STR_SZ,
7397 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007398 " Phy Disabled",PhyNumber);
7399 break;
7400 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06007401 snprintf(evStr, EVENT_DESCR_STR_SZ,
7402 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007403 " Failed Speed Nego",PhyNumber);
7404 break;
7405 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06007406 snprintf(evStr, EVENT_DESCR_STR_SZ,
7407 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007408 " Sata OOB Completed",PhyNumber);
7409 break;
7410 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06007411 snprintf(evStr, EVENT_DESCR_STR_SZ,
7412 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007413 " Rate 1.5 Gbps",PhyNumber);
7414 break;
7415 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06007416 snprintf(evStr, EVENT_DESCR_STR_SZ,
7417 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007418 " Rate 3.0 Gpbs",PhyNumber);
7419 break;
7420 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007421 snprintf(evStr, EVENT_DESCR_STR_SZ,
7422 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007423 break;
7424 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007425 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007426 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007427 case MPI_EVENT_SAS_DISCOVERY_ERROR:
7428 ds = "SAS Discovery Error";
7429 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007430 case MPI_EVENT_IR_RESYNC_UPDATE:
7431 {
7432 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06007433 snprintf(evStr, EVENT_DESCR_STR_SZ,
7434 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07007435 break;
7436 }
7437 case MPI_EVENT_IR2:
7438 {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307439 u8 id = (u8)(evData0);
7440 u8 channel = (u8)(evData0 >> 8);
7441 u8 phys_num = (u8)(evData0 >> 24);
Moore, Eric3a892be2006-03-14 09:14:03 -07007442 u8 ReasonCode = (u8)(evData0 >> 16);
Kashyap, Desai2f187862009-05-29 16:52:37 +05307443
Moore, Eric3a892be2006-03-14 09:14:03 -07007444 switch (ReasonCode) {
7445 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307446 snprintf(evStr, EVENT_DESCR_STR_SZ,
7447 "IR2: LD State Changed: "
7448 "id=%d channel=%d phys_num=%d",
7449 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007450 break;
7451 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307452 snprintf(evStr, EVENT_DESCR_STR_SZ,
7453 "IR2: PD State Changed "
7454 "id=%d channel=%d phys_num=%d",
7455 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007456 break;
7457 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307458 snprintf(evStr, EVENT_DESCR_STR_SZ,
7459 "IR2: Bad Block Table Full: "
7460 "id=%d channel=%d phys_num=%d",
7461 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007462 break;
7463 case MPI_EVENT_IR2_RC_PD_INSERTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307464 snprintf(evStr, EVENT_DESCR_STR_SZ,
7465 "IR2: PD Inserted: "
7466 "id=%d channel=%d phys_num=%d",
7467 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007468 break;
7469 case MPI_EVENT_IR2_RC_PD_REMOVED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307470 snprintf(evStr, EVENT_DESCR_STR_SZ,
7471 "IR2: PD Removed: "
7472 "id=%d channel=%d phys_num=%d",
7473 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007474 break;
7475 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307476 snprintf(evStr, EVENT_DESCR_STR_SZ,
7477 "IR2: Foreign CFG Detected: "
7478 "id=%d channel=%d phys_num=%d",
7479 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007480 break;
7481 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307482 snprintf(evStr, EVENT_DESCR_STR_SZ,
7483 "IR2: Rebuild Medium Error: "
7484 "id=%d channel=%d phys_num=%d",
7485 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007486 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05307487 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
7488 snprintf(evStr, EVENT_DESCR_STR_SZ,
7489 "IR2: Dual Port Added: "
7490 "id=%d channel=%d phys_num=%d",
7491 id, channel, phys_num);
7492 break;
7493 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
7494 snprintf(evStr, EVENT_DESCR_STR_SZ,
7495 "IR2: Dual Port Removed: "
7496 "id=%d channel=%d phys_num=%d",
7497 id, channel, phys_num);
7498 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007499 default:
7500 ds = "IR2";
7501 break;
7502 }
7503 break;
7504 }
7505 case MPI_EVENT_SAS_DISCOVERY:
7506 {
7507 if (evData0)
7508 ds = "SAS Discovery: Start";
7509 else
7510 ds = "SAS Discovery: Stop";
7511 break;
7512 }
7513 case MPI_EVENT_LOG_ENTRY_ADDED:
7514 ds = "SAS Log Entry Added";
7515 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007516
Eric Moorec6c727a2007-01-29 09:44:54 -07007517 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
7518 {
7519 u8 phy_num = (u8)(evData0);
7520 u8 port_num = (u8)(evData0 >> 8);
7521 u8 port_width = (u8)(evData0 >> 16);
7522 u8 primative = (u8)(evData0 >> 24);
7523 snprintf(evStr, EVENT_DESCR_STR_SZ,
7524 "SAS Broadcase Primative: phy=%d port=%d "
7525 "width=%d primative=0x%02x",
7526 phy_num, port_num, port_width, primative);
7527 break;
7528 }
7529
7530 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7531 {
7532 u8 reason = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007533
Kashyap, Desai2f187862009-05-29 16:52:37 +05307534 switch (reason) {
7535 case MPI_EVENT_SAS_INIT_RC_ADDED:
7536 ds = "SAS Initiator Status Change: Added";
7537 break;
7538 case MPI_EVENT_SAS_INIT_RC_REMOVED:
7539 ds = "SAS Initiator Status Change: Deleted";
7540 break;
7541 default:
7542 ds = "SAS Initiator Status Change";
7543 break;
7544 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007545 break;
7546 }
7547
7548 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7549 {
7550 u8 max_init = (u8)(evData0);
7551 u8 current_init = (u8)(evData0 >> 8);
7552
7553 snprintf(evStr, EVENT_DESCR_STR_SZ,
7554 "SAS Initiator Device Table Overflow: max initiators=%02d "
7555 "current initators=%02d",
7556 max_init, current_init);
7557 break;
7558 }
7559 case MPI_EVENT_SAS_SMP_ERROR:
7560 {
7561 u8 status = (u8)(evData0);
7562 u8 port_num = (u8)(evData0 >> 8);
7563 u8 result = (u8)(evData0 >> 16);
7564
7565 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7566 snprintf(evStr, EVENT_DESCR_STR_SZ,
7567 "SAS SMP Error: port=%d result=0x%02x",
7568 port_num, result);
7569 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7570 snprintf(evStr, EVENT_DESCR_STR_SZ,
7571 "SAS SMP Error: port=%d : CRC Error",
7572 port_num);
7573 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7574 snprintf(evStr, EVENT_DESCR_STR_SZ,
7575 "SAS SMP Error: port=%d : Timeout",
7576 port_num);
7577 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7578 snprintf(evStr, EVENT_DESCR_STR_SZ,
7579 "SAS SMP Error: port=%d : No Destination",
7580 port_num);
7581 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7582 snprintf(evStr, EVENT_DESCR_STR_SZ,
7583 "SAS SMP Error: port=%d : Bad Destination",
7584 port_num);
7585 else
7586 snprintf(evStr, EVENT_DESCR_STR_SZ,
7587 "SAS SMP Error: port=%d : status=0x%02x",
7588 port_num, status);
7589 break;
7590 }
7591
Kashyap, Desai2f187862009-05-29 16:52:37 +05307592 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
7593 {
7594 u8 reason = (u8)(evData0);
7595
7596 switch (reason) {
7597 case MPI_EVENT_SAS_EXP_RC_ADDED:
7598 ds = "Expander Status Change: Added";
7599 break;
7600 case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
7601 ds = "Expander Status Change: Deleted";
7602 break;
7603 default:
7604 ds = "Expander Status Change";
7605 break;
7606 }
7607 break;
7608 }
7609
Linus Torvalds1da177e2005-04-16 15:20:36 -07007610 /*
7611 * MPT base "custom" events may be added here...
7612 */
7613 default:
7614 ds = "Unknown";
7615 break;
7616 }
Eric Moore509e5e52006-04-26 13:22:37 -06007617 if (ds)
7618 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007619
Kashyap, Desai2f187862009-05-29 16:52:37 +05307620
7621 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7622 "MPT event:(%02Xh) : %s\n",
7623 ioc->name, event, evStr));
7624
7625 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
7626 ": Event data:\n"));
7627 for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
7628 devtverboseprintk(ioc, printk(" %08x",
7629 le32_to_cpu(pEventReply->Data[ii])));
7630 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
7631}
7632#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007633/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007634/**
7635 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007636 * @ioc: Pointer to MPT_ADAPTER structure
7637 * @pEventReply: Pointer to EventNotification reply frame
7638 * @evHandlers: Pointer to integer, number of event handlers
7639 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007640 * Routes a received EventNotificationReply to all currently registered
7641 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007642 * Returns sum of event handlers return values.
7643 */
7644static int
7645ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7646{
7647 u16 evDataLen;
7648 u32 evData0 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007649 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307650 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007651 int r = 0;
7652 int handlers = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007653 u8 event;
7654
7655 /*
7656 * Do platform normalization of values
7657 */
7658 event = le32_to_cpu(pEventReply->Event) & 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007659 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7660 if (evDataLen) {
7661 evData0 = le32_to_cpu(pEventReply->Data[0]);
7662 }
7663
Prakash, Sathya436ace72007-07-24 15:42:08 +05307664#ifdef CONFIG_FUSION_LOGGING
Kashyap, Desai2f187862009-05-29 16:52:37 +05307665 if (evDataLen)
7666 mpt_display_event_info(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007667#endif
7668
7669 /*
7670 * Do general / base driver event processing
7671 */
7672 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007673 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7674 if (evDataLen) {
7675 u8 evState = evData0 & 0xFF;
7676
7677 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7678
7679 /* Update EventState field in cached IocFacts */
7680 if (ioc->facts.Function) {
7681 ioc->facts.EventState = evState;
7682 }
7683 }
7684 break;
Moore, Ericece50912006-01-16 18:53:19 -07007685 case MPI_EVENT_INTEGRATED_RAID:
7686 mptbase_raid_process_event_data(ioc,
7687 (MpiEventDataRaid_t *)pEventReply->Data);
7688 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007689 default:
7690 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007691 }
7692
7693 /*
7694 * Should this event be logged? Events are written sequentially.
7695 * When buffer is full, start again at the top.
7696 */
7697 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7698 int idx;
7699
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007700 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007701
7702 ioc->events[idx].event = event;
7703 ioc->events[idx].eventContext = ioc->eventContext;
7704
7705 for (ii = 0; ii < 2; ii++) {
7706 if (ii < evDataLen)
7707 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7708 else
7709 ioc->events[idx].data[ii] = 0;
7710 }
7711
7712 ioc->eventContext++;
7713 }
7714
7715
7716 /*
7717 * Call each currently registered protocol event handler.
7718 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007719 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307720 if (MptEvHandlers[cb_idx]) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307721 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7722 "Routing Event to event handler #%d\n",
7723 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307724 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007725 handlers++;
7726 }
7727 }
7728 /* FIXME? Examine results here? */
7729
7730 /*
7731 * If needed, send (a single) EventAck.
7732 */
7733 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307734 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007735 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007736 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307737 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007738 ioc->name, ii));
7739 }
7740 }
7741
7742 *evHandlers = handlers;
7743 return r;
7744}
7745
7746/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007747/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007748 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7749 * @ioc: Pointer to MPT_ADAPTER structure
7750 * @log_info: U32 LogInfo reply word from the IOC
7751 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007752 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007753 */
7754static void
7755mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7756{
Eric Moore7c431e52007-06-13 16:34:36 -06007757 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007758
Eric Moore7c431e52007-06-13 16:34:36 -06007759 switch (log_info & 0xFF000000) {
7760 case MPI_IOCLOGINFO_FC_INIT_BASE:
7761 desc = "FCP Initiator";
7762 break;
7763 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7764 desc = "FCP Target";
7765 break;
7766 case MPI_IOCLOGINFO_FC_LAN_BASE:
7767 desc = "LAN";
7768 break;
7769 case MPI_IOCLOGINFO_FC_MSG_BASE:
7770 desc = "MPI Message Layer";
7771 break;
7772 case MPI_IOCLOGINFO_FC_LINK_BASE:
7773 desc = "FC Link";
7774 break;
7775 case MPI_IOCLOGINFO_FC_CTX_BASE:
7776 desc = "Context Manager";
7777 break;
7778 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7779 desc = "Invalid Field Offset";
7780 break;
7781 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7782 desc = "State Change Info";
7783 break;
7784 }
7785
7786 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7787 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007788}
7789
7790/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007791/**
Moore, Eric335a9412006-01-17 17:06:23 -07007792 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007793 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007794 * @log_info: U32 LogInfo word from the IOC
7795 *
7796 * Refer to lsi/sp_log.h.
7797 */
7798static void
Moore, Eric335a9412006-01-17 17:06:23 -07007799mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007800{
7801 u32 info = log_info & 0x00FF0000;
7802 char *desc = "unknown";
7803
7804 switch (info) {
7805 case 0x00010000:
7806 desc = "bug! MID not found";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007807 break;
7808
7809 case 0x00020000:
7810 desc = "Parity Error";
7811 break;
7812
7813 case 0x00030000:
7814 desc = "ASYNC Outbound Overrun";
7815 break;
7816
7817 case 0x00040000:
7818 desc = "SYNC Offset Error";
7819 break;
7820
7821 case 0x00050000:
7822 desc = "BM Change";
7823 break;
7824
7825 case 0x00060000:
7826 desc = "Msg In Overflow";
7827 break;
7828
7829 case 0x00070000:
7830 desc = "DMA Error";
7831 break;
7832
7833 case 0x00080000:
7834 desc = "Outbound DMA Overrun";
7835 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007836
Linus Torvalds1da177e2005-04-16 15:20:36 -07007837 case 0x00090000:
7838 desc = "Task Management";
7839 break;
7840
7841 case 0x000A0000:
7842 desc = "Device Problem";
7843 break;
7844
7845 case 0x000B0000:
7846 desc = "Invalid Phase Change";
7847 break;
7848
7849 case 0x000C0000:
7850 desc = "Untagged Table Size";
7851 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007852
Linus Torvalds1da177e2005-04-16 15:20:36 -07007853 }
7854
7855 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7856}
7857
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007858/* strings for sas loginfo */
7859 static char *originator_str[] = {
7860 "IOP", /* 00h */
7861 "PL", /* 01h */
7862 "IR" /* 02h */
7863 };
7864 static char *iop_code_str[] = {
7865 NULL, /* 00h */
7866 "Invalid SAS Address", /* 01h */
7867 NULL, /* 02h */
7868 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007869 "Diag Message Error", /* 04h */
7870 "Task Terminated", /* 05h */
7871 "Enclosure Management", /* 06h */
7872 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007873 };
7874 static char *pl_code_str[] = {
7875 NULL, /* 00h */
7876 "Open Failure", /* 01h */
7877 "Invalid Scatter Gather List", /* 02h */
7878 "Wrong Relative Offset or Frame Length", /* 03h */
7879 "Frame Transfer Error", /* 04h */
7880 "Transmit Frame Connected Low", /* 05h */
7881 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7882 "SATA Read Log Receive Data Error", /* 07h */
7883 "SATA NCQ Fail All Commands After Error", /* 08h */
7884 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7885 "Receive Frame Invalid Message", /* 0Ah */
7886 "Receive Context Message Valid Error", /* 0Bh */
7887 "Receive Frame Current Frame Error", /* 0Ch */
7888 "SATA Link Down", /* 0Dh */
7889 "Discovery SATA Init W IOS", /* 0Eh */
7890 "Config Invalid Page", /* 0Fh */
7891 "Discovery SATA Init Timeout", /* 10h */
7892 "Reset", /* 11h */
7893 "Abort", /* 12h */
7894 "IO Not Yet Executed", /* 13h */
7895 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007896 "Persistent Reservation Out Not Affiliation "
7897 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007898 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007899 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007900 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007901 NULL, /* 19h */
7902 NULL, /* 1Ah */
7903 NULL, /* 1Bh */
7904 NULL, /* 1Ch */
7905 NULL, /* 1Dh */
7906 NULL, /* 1Eh */
7907 NULL, /* 1Fh */
7908 "Enclosure Management" /* 20h */
7909 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007910 static char *ir_code_str[] = {
7911 "Raid Action Error", /* 00h */
7912 NULL, /* 00h */
7913 NULL, /* 01h */
7914 NULL, /* 02h */
7915 NULL, /* 03h */
7916 NULL, /* 04h */
7917 NULL, /* 05h */
7918 NULL, /* 06h */
7919 NULL /* 07h */
7920 };
7921 static char *raid_sub_code_str[] = {
7922 NULL, /* 00h */
7923 "Volume Creation Failed: Data Passed too "
7924 "Large", /* 01h */
7925 "Volume Creation Failed: Duplicate Volumes "
7926 "Attempted", /* 02h */
7927 "Volume Creation Failed: Max Number "
7928 "Supported Volumes Exceeded", /* 03h */
7929 "Volume Creation Failed: DMA Error", /* 04h */
7930 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7931 "Volume Creation Failed: Error Reading "
7932 "MFG Page 4", /* 06h */
7933 "Volume Creation Failed: Creating Internal "
7934 "Structures", /* 07h */
7935 NULL, /* 08h */
7936 NULL, /* 09h */
7937 NULL, /* 0Ah */
7938 NULL, /* 0Bh */
7939 NULL, /* 0Ch */
7940 NULL, /* 0Dh */
7941 NULL, /* 0Eh */
7942 NULL, /* 0Fh */
7943 "Activation failed: Already Active Volume", /* 10h */
7944 "Activation failed: Unsupported Volume Type", /* 11h */
7945 "Activation failed: Too Many Active Volumes", /* 12h */
7946 "Activation failed: Volume ID in Use", /* 13h */
7947 "Activation failed: Reported Failure", /* 14h */
7948 "Activation failed: Importing a Volume", /* 15h */
7949 NULL, /* 16h */
7950 NULL, /* 17h */
7951 NULL, /* 18h */
7952 NULL, /* 19h */
7953 NULL, /* 1Ah */
7954 NULL, /* 1Bh */
7955 NULL, /* 1Ch */
7956 NULL, /* 1Dh */
7957 NULL, /* 1Eh */
7958 NULL, /* 1Fh */
7959 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7960 "Phys Disk failed: Data Passed too Large", /* 21h */
7961 "Phys Disk failed: DMA Error", /* 22h */
7962 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7963 "Phys Disk failed: Creating Phys Disk Config "
7964 "Page", /* 24h */
7965 NULL, /* 25h */
7966 NULL, /* 26h */
7967 NULL, /* 27h */
7968 NULL, /* 28h */
7969 NULL, /* 29h */
7970 NULL, /* 2Ah */
7971 NULL, /* 2Bh */
7972 NULL, /* 2Ch */
7973 NULL, /* 2Dh */
7974 NULL, /* 2Eh */
7975 NULL, /* 2Fh */
7976 "Compatibility Error: IR Disabled", /* 30h */
7977 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7978 "Compatibility Error: Device not Direct Access "
7979 "Device ", /* 32h */
7980 "Compatibility Error: Removable Device Found", /* 33h */
7981 "Compatibility Error: Device SCSI Version not "
7982 "2 or Higher", /* 34h */
7983 "Compatibility Error: SATA Device, 48 BIT LBA "
7984 "not Supported", /* 35h */
7985 "Compatibility Error: Device doesn't have "
7986 "512 Byte Block Sizes", /* 36h */
7987 "Compatibility Error: Volume Type Check Failed", /* 37h */
7988 "Compatibility Error: Volume Type is "
7989 "Unsupported by FW", /* 38h */
7990 "Compatibility Error: Disk Drive too Small for "
7991 "use in Volume", /* 39h */
7992 "Compatibility Error: Phys Disk for Create "
7993 "Volume not Found", /* 3Ah */
7994 "Compatibility Error: Too Many or too Few "
7995 "Disks for Volume Type", /* 3Bh */
7996 "Compatibility Error: Disk stripe Sizes "
7997 "Must be 64KB", /* 3Ch */
7998 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7999 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008000
8001/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008002/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008003 * mpt_sas_log_info - Log information returned from SAS IOC.
8004 * @ioc: Pointer to MPT_ADAPTER structure
8005 * @log_info: U32 LogInfo reply word from the IOC
8006 *
8007 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008008 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008009static void
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308010mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info, u8 cb_idx)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008011{
8012union loginfo_type {
8013 u32 loginfo;
8014 struct {
8015 u32 subcode:16;
8016 u32 code:8;
8017 u32 originator:4;
8018 u32 bus_type:4;
8019 }dw;
8020};
8021 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07008022 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008023 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07008024 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008025
8026 sas_loginfo.loginfo = log_info;
8027 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008028 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008029 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07008030
8031 originator_desc = originator_str[sas_loginfo.dw.originator];
8032
8033 switch (sas_loginfo.dw.originator) {
8034
8035 case 0: /* IOP */
8036 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008037 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008038 code_desc = iop_code_str[sas_loginfo.dw.code];
8039 break;
8040 case 1: /* PL */
8041 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008042 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008043 code_desc = pl_code_str[sas_loginfo.dw.code];
8044 break;
8045 case 2: /* IR */
8046 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008047 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008048 break;
8049 code_desc = ir_code_str[sas_loginfo.dw.code];
8050 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008051 ARRAY_SIZE(raid_sub_code_str))
Julia Lawall081f4f42010-08-05 22:27:14 +02008052 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07008053 if (sas_loginfo.dw.code == 0)
8054 sub_code_desc =
8055 raid_sub_code_str[sas_loginfo.dw.subcode];
8056 break;
8057 default:
8058 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008059 }
8060
Eric Moorec6c727a2007-01-29 09:44:54 -07008061 if (sub_code_desc != NULL)
8062 printk(MYIOC_s_INFO_FMT
8063 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308064 " SubCode={%s} cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008065 ioc->name, log_info, originator_desc, code_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308066 sub_code_desc, MptCallbacksName[cb_idx]);
Eric Moorec6c727a2007-01-29 09:44:54 -07008067 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008068 printk(MYIOC_s_INFO_FMT
8069 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308070 " SubCode(0x%04x) cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008071 ioc->name, log_info, originator_desc, code_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308072 sas_loginfo.dw.subcode, MptCallbacksName[cb_idx]);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008073 else
8074 printk(MYIOC_s_INFO_FMT
8075 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308076 " SubCode(0x%04x) cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008077 ioc->name, log_info, originator_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308078 sas_loginfo.dw.code, sas_loginfo.dw.subcode,
8079 MptCallbacksName[cb_idx]);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008080}
8081
Linus Torvalds1da177e2005-04-16 15:20:36 -07008082/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008083/**
Eric Moorec6c727a2007-01-29 09:44:54 -07008084 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
8085 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08008086 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07008087 * @mf: Pointer to MPT request frame
8088 *
8089 * Refer to lsi/mpi.h.
8090 **/
8091static void
8092mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
8093{
8094 Config_t *pReq = (Config_t *)mf;
8095 char extend_desc[EVENT_DESCR_STR_SZ];
8096 char *desc = NULL;
8097 u32 form;
8098 u8 page_type;
8099
8100 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
8101 page_type = pReq->ExtPageType;
8102 else
8103 page_type = pReq->Header.PageType;
8104
8105 /*
8106 * ignore invalid page messages for GET_NEXT_HANDLE
8107 */
8108 form = le32_to_cpu(pReq->PageAddress);
8109 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
8110 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
8111 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
8112 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
8113 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
8114 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
8115 return;
8116 }
8117 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
8118 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
8119 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
8120 return;
8121 }
8122
8123 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
8124 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
8125 page_type, pReq->Header.PageNumber, pReq->Action, form);
8126
8127 switch (ioc_status) {
8128
8129 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8130 desc = "Config Page Invalid Action";
8131 break;
8132
8133 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8134 desc = "Config Page Invalid Type";
8135 break;
8136
8137 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8138 desc = "Config Page Invalid Page";
8139 break;
8140
8141 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8142 desc = "Config Page Invalid Data";
8143 break;
8144
8145 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8146 desc = "Config Page No Defaults";
8147 break;
8148
8149 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
8150 desc = "Config Page Can't Commit";
8151 break;
8152 }
8153
8154 if (!desc)
8155 return;
8156
Eric Moore29dd3602007-09-14 18:46:51 -06008157 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
8158 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07008159}
8160
8161/**
8162 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07008163 * @ioc: Pointer to MPT_ADAPTER structure
8164 * @ioc_status: U32 IOCStatus word from IOC
8165 * @mf: Pointer to MPT request frame
8166 *
8167 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008168 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07008169static void
Eric Moorec6c727a2007-01-29 09:44:54 -07008170mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008171{
8172 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06008173 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008174
8175 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07008176
8177/****************************************************************************/
8178/* Common IOCStatus values for all replies */
8179/****************************************************************************/
8180
Linus Torvalds1da177e2005-04-16 15:20:36 -07008181 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
8182 desc = "Invalid Function";
8183 break;
8184
8185 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
8186 desc = "Busy";
8187 break;
8188
8189 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
8190 desc = "Invalid SGL";
8191 break;
8192
8193 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
8194 desc = "Internal Error";
8195 break;
8196
8197 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
8198 desc = "Reserved";
8199 break;
8200
8201 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
8202 desc = "Insufficient Resources";
8203 break;
8204
8205 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
8206 desc = "Invalid Field";
8207 break;
8208
8209 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
8210 desc = "Invalid State";
8211 break;
8212
Eric Moorec6c727a2007-01-29 09:44:54 -07008213/****************************************************************************/
8214/* Config IOCStatus values */
8215/****************************************************************************/
8216
Linus Torvalds1da177e2005-04-16 15:20:36 -07008217 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8218 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8219 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8220 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8221 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8222 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008223 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008224 break;
8225
Eric Moorec6c727a2007-01-29 09:44:54 -07008226/****************************************************************************/
8227/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
8228/* */
8229/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
8230/* */
8231/****************************************************************************/
8232
Linus Torvalds1da177e2005-04-16 15:20:36 -07008233 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008234 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008235 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
8236 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
8237 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
8238 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008239 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008240 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008241 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008242 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008243 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008244 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07008245 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008246 break;
8247
Eric Moorec6c727a2007-01-29 09:44:54 -07008248/****************************************************************************/
8249/* SCSI Target values */
8250/****************************************************************************/
8251
8252 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
8253 desc = "Target: Priority IO";
8254 break;
8255
8256 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
8257 desc = "Target: Invalid Port";
8258 break;
8259
8260 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
8261 desc = "Target Invalid IO Index:";
8262 break;
8263
8264 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
8265 desc = "Target: Aborted";
8266 break;
8267
8268 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
8269 desc = "Target: No Conn Retryable";
8270 break;
8271
8272 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
8273 desc = "Target: No Connection";
8274 break;
8275
8276 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
8277 desc = "Target: Transfer Count Mismatch";
8278 break;
8279
8280 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
8281 desc = "Target: STS Data not Sent";
8282 break;
8283
8284 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
8285 desc = "Target: Data Offset Error";
8286 break;
8287
8288 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
8289 desc = "Target: Too Much Write Data";
8290 break;
8291
8292 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
8293 desc = "Target: IU Too Short";
8294 break;
8295
8296 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
8297 desc = "Target: ACK NAK Timeout";
8298 break;
8299
8300 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
8301 desc = "Target: Nak Received";
8302 break;
8303
8304/****************************************************************************/
8305/* Fibre Channel Direct Access values */
8306/****************************************************************************/
8307
8308 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
8309 desc = "FC: Aborted";
8310 break;
8311
8312 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
8313 desc = "FC: RX ID Invalid";
8314 break;
8315
8316 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
8317 desc = "FC: DID Invalid";
8318 break;
8319
8320 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
8321 desc = "FC: Node Logged Out";
8322 break;
8323
8324 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
8325 desc = "FC: Exchange Canceled";
8326 break;
8327
8328/****************************************************************************/
8329/* LAN values */
8330/****************************************************************************/
8331
8332 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
8333 desc = "LAN: Device not Found";
8334 break;
8335
8336 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
8337 desc = "LAN: Device Failure";
8338 break;
8339
8340 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
8341 desc = "LAN: Transmit Error";
8342 break;
8343
8344 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
8345 desc = "LAN: Transmit Aborted";
8346 break;
8347
8348 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
8349 desc = "LAN: Receive Error";
8350 break;
8351
8352 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
8353 desc = "LAN: Receive Aborted";
8354 break;
8355
8356 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
8357 desc = "LAN: Partial Packet";
8358 break;
8359
8360 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
8361 desc = "LAN: Canceled";
8362 break;
8363
8364/****************************************************************************/
8365/* Serial Attached SCSI values */
8366/****************************************************************************/
8367
8368 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
8369 desc = "SAS: SMP Request Failed";
8370 break;
8371
8372 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
8373 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07008374 break;
8375
8376 default:
8377 desc = "Others";
8378 break;
8379 }
Eric Moorec6c727a2007-01-29 09:44:54 -07008380
8381 if (!desc)
8382 return;
8383
Eric Moore29dd3602007-09-14 18:46:51 -06008384 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
8385 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008386}
8387
8388/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008389EXPORT_SYMBOL(mpt_attach);
8390EXPORT_SYMBOL(mpt_detach);
8391#ifdef CONFIG_PM
8392EXPORT_SYMBOL(mpt_resume);
8393EXPORT_SYMBOL(mpt_suspend);
8394#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07008395EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008396EXPORT_SYMBOL(mpt_register);
8397EXPORT_SYMBOL(mpt_deregister);
8398EXPORT_SYMBOL(mpt_event_register);
8399EXPORT_SYMBOL(mpt_event_deregister);
8400EXPORT_SYMBOL(mpt_reset_register);
8401EXPORT_SYMBOL(mpt_reset_deregister);
8402EXPORT_SYMBOL(mpt_device_driver_register);
8403EXPORT_SYMBOL(mpt_device_driver_deregister);
8404EXPORT_SYMBOL(mpt_get_msg_frame);
8405EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05308406EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008407EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008408EXPORT_SYMBOL(mpt_send_handshake_request);
8409EXPORT_SYMBOL(mpt_verify_adapter);
8410EXPORT_SYMBOL(mpt_GetIocState);
8411EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008412EXPORT_SYMBOL(mpt_HardResetHandler);
8413EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008414EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008415EXPORT_SYMBOL(mpt_alloc_fw_memory);
8416EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02008417EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07008418EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008419
Linus Torvalds1da177e2005-04-16 15:20:36 -07008420/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008421/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008422 * fusion_init - Fusion MPT base driver initialization routine.
8423 *
8424 * Returns 0 for success, non-zero for failure.
8425 */
8426static int __init
8427fusion_init(void)
8428{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308429 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008430
8431 show_mptmod_ver(my_NAME, my_VERSION);
8432 printk(KERN_INFO COPYRIGHT "\n");
8433
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308434 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
8435 MptCallbacks[cb_idx] = NULL;
8436 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
8437 MptEvHandlers[cb_idx] = NULL;
8438 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008439 }
8440
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008441 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07008442 * EventNotification handling.
8443 */
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308444 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER,
8445 "mptbase_reply");
Linus Torvalds1da177e2005-04-16 15:20:36 -07008446
8447 /* Register for hard reset handling callbacks.
8448 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05308449 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008450
8451#ifdef CONFIG_PROC_FS
8452 (void) procmpt_create();
8453#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008454 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008455}
8456
8457/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008458/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008459 * fusion_exit - Perform driver unload cleanup.
8460 *
8461 * This routine frees all resources associated with each MPT adapter
8462 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
8463 */
8464static void __exit
8465fusion_exit(void)
8466{
8467
Linus Torvalds1da177e2005-04-16 15:20:36 -07008468 mpt_reset_deregister(mpt_base_index);
8469
8470#ifdef CONFIG_PROC_FS
8471 procmpt_destroy();
8472#endif
8473}
8474
Linus Torvalds1da177e2005-04-16 15:20:36 -07008475module_init(fusion_init);
8476module_exit(fusion_exit);