blob: 7956a10f94885f19cc91dc981c5934fcb494a414 [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);
Joe Perches85ee7a12011-04-23 20:38:19 -070086MODULE_PARM_DESC(mpt_msi_enable_spi,
87 " Enable MSI Support for SPI controllers (default=0)");
Kashyap, Desaie3829682009-01-08 14:27:16 +053088
89static int mpt_msi_enable_fc;
90module_param(mpt_msi_enable_fc, int, 0);
Joe Perches85ee7a12011-04-23 20:38:19 -070091MODULE_PARM_DESC(mpt_msi_enable_fc,
92 " Enable MSI Support for FC controllers (default=0)");
Kashyap, Desaie3829682009-01-08 14:27:16 +053093
94static int mpt_msi_enable_sas;
Yinghai Lu5ce78682009-02-18 11:25:32 -080095module_param(mpt_msi_enable_sas, int, 0);
Joe Perches85ee7a12011-04-23 20:38:19 -070096MODULE_PARM_DESC(mpt_msi_enable_sas,
97 " Enable MSI Support for SAS controllers (default=0)");
Christoph Hellwig4ddce142006-01-17 13:44:29 +000098
Eric Moore793955f2007-01-29 09:42:20 -070099static int mpt_channel_mapping;
100module_param(mpt_channel_mapping, int, 0);
101MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
102
Prakash, Sathya436ace72007-07-24 15:42:08 +0530103static int mpt_debug_level;
James Bottomleydb47c2d2007-07-28 13:40:21 -0400104static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
105module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
106 &mpt_debug_level, 0600);
Joe Perches85ee7a12011-04-23 20:38:19 -0700107MODULE_PARM_DESC(mpt_debug_level,
108 " debug level - refer to mptdebug.h - (default=0)");
Kashyap, Desaie3829682009-01-08 14:27:16 +0530109
Kashyap, Desai2f4c7822009-01-06 15:03:37 +0530110int mpt_fwfault_debug;
111EXPORT_SYMBOL(mpt_fwfault_debug);
Rusty Russell57ba4712010-08-11 23:04:39 -0600112module_param(mpt_fwfault_debug, int, 0600);
Joe Perches85ee7a12011-04-23 20:38:19 -0700113MODULE_PARM_DESC(mpt_fwfault_debug,
114 "Enable detection of Firmware fault and halt Firmware on fault - (default=0)");
Kashyap, Desai2f4c7822009-01-06 15:03:37 +0530115
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530116static char MptCallbacksName[MPT_MAX_PROTOCOL_DRIVERS][50];
Prakash, Sathya436ace72007-07-24 15:42:08 +0530117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118#ifdef MFCNT
119static int mfcounter = 0;
120#define PRINT_MF_COUNT 20000
121#endif
122
123/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
124/*
125 * Public data...
126 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128#define WHOINIT_UNKNOWN 0xAA
129
130/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
131/*
132 * Private data...
133 */
134 /* Adapter link list */
135LIST_HEAD(ioc_list);
136 /* Callback lookup table */
137static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
138 /* Protocol driver class lookup table */
139static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
140 /* Event handler lookup table */
141static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
142 /* Reset handler lookup table */
143static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
144static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
145
Erik Ekmane47c11c2009-12-14 21:21:56 +0100146#ifdef CONFIG_PROC_FS
147static struct proc_dir_entry *mpt_proc_root_dir;
148#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530150/*
151 * Driver Callback Index's
152 */
153static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
154static u8 last_drv_idx;
155
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
157/*
158 * Forward protos...
159 */
David Howells7d12e782006-10-05 14:55:46 +0100160static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530161static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
162 MPT_FRAME_HDR *reply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
164 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
165 int sleepFlag);
166static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
167static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
168static void mpt_adapter_disable(MPT_ADAPTER *ioc);
169static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
170
171static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
172static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
174static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
175static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
176static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
177static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200178static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
180static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
181static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
182static int PrimeIocFifos(MPT_ADAPTER *ioc);
183static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
184static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
185static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
186static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200188int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
190static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
191static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
192static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530193static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Kashyap, Desaifd761752009-05-29 16:39:06 +0530194static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch,
195 int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200197static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
198static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
200#ifdef CONFIG_PROC_FS
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -0700201static const struct file_operations mpt_summary_proc_fops;
202static const struct file_operations mpt_version_proc_fops;
203static const struct file_operations mpt_iocinfo_proc_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204#endif
205static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
206
Kashyap, Desaifd761752009-05-29 16:39:06 +0530207static int ProcessEventNotification(MPT_ADAPTER *ioc,
208 EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700209static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700211static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530212static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info , u8 cb_idx);
Moore, Ericc972c702006-03-14 09:14:06 -0700213static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700214static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
216/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217static int __init fusion_init (void);
218static void __exit fusion_exit (void);
219
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220#define CHIPREG_READ32(addr) readl_relaxed(addr)
221#define CHIPREG_READ32_dmasync(addr) readl(addr)
222#define CHIPREG_WRITE32(addr,val) writel(val, addr)
223#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
224#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
225
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600226static void
227pci_disable_io_access(struct pci_dev *pdev)
228{
229 u16 command_reg;
230
231 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
232 command_reg &= ~1;
233 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
234}
235
236static void
237pci_enable_io_access(struct pci_dev *pdev)
238{
239 u16 command_reg;
240
241 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
242 command_reg |= 1;
243 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
244}
245
James Bottomleydb47c2d2007-07-28 13:40:21 -0400246static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
247{
248 int ret = param_set_int(val, kp);
249 MPT_ADAPTER *ioc;
250
251 if (ret)
252 return ret;
253
254 list_for_each_entry(ioc, &ioc_list, list)
255 ioc->debug_level = mpt_debug_level;
256 return 0;
257}
258
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530259/**
260 * mpt_get_cb_idx - obtain cb_idx for registered driver
261 * @dclass: class driver enum
262 *
263 * Returns cb_idx, or zero means it wasn't found
264 **/
265static u8
266mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
267{
268 u8 cb_idx;
269
270 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
271 if (MptDriverClass[cb_idx] == dclass)
272 return cb_idx;
273 return 0;
274}
275
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530276/**
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530277 * mpt_is_discovery_complete - determine if discovery has completed
278 * @ioc: per adatper instance
279 *
280 * Returns 1 when discovery completed, else zero.
281 */
282static int
283mpt_is_discovery_complete(MPT_ADAPTER *ioc)
284{
285 ConfigExtendedPageHeader_t hdr;
286 CONFIGPARMS cfg;
287 SasIOUnitPage0_t *buffer;
288 dma_addr_t dma_handle;
289 int rc = 0;
290
291 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
292 memset(&cfg, 0, sizeof(CONFIGPARMS));
293 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
294 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
295 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
296 cfg.cfghdr.ehdr = &hdr;
297 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
298
299 if ((mpt_config(ioc, &cfg)))
300 goto out;
301 if (!hdr.ExtPageLength)
302 goto out;
303
304 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
305 &dma_handle);
306 if (!buffer)
307 goto out;
308
309 cfg.physAddr = dma_handle;
310 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
311
312 if ((mpt_config(ioc, &cfg)))
313 goto out_free_consistent;
314
315 if (!(buffer->PhyData[0].PortFlags &
316 MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS))
317 rc = 1;
318
319 out_free_consistent:
320 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
321 buffer, dma_handle);
322 out:
323 return rc;
324}
325
326/**
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530327 * mpt_fault_reset_work - work performed on workq after ioc fault
328 * @work: input argument, used to derive ioc
329 *
330**/
331static void
332mpt_fault_reset_work(struct work_struct *work)
333{
334 MPT_ADAPTER *ioc =
335 container_of(work, MPT_ADAPTER, fault_reset_work.work);
336 u32 ioc_raw_state;
337 int rc;
338 unsigned long flags;
339
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530340 if (ioc->ioc_reset_in_progress || !ioc->active)
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530341 goto out;
342
343 ioc_raw_state = mpt_GetIocState(ioc, 0);
344 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
345 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700346 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530347 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700348 ioc->name, __func__);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530349 rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
350 printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700351 __func__, (rc == 0) ? "success" : "failed");
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530352 ioc_raw_state = mpt_GetIocState(ioc, 0);
353 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
354 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
355 "reset (%04xh)\n", ioc->name, ioc_raw_state &
356 MPI_DOORBELL_DATA_MASK);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530357 } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) {
358 if ((mpt_is_discovery_complete(ioc))) {
359 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing "
360 "discovery_quiesce_io flag\n", ioc->name));
361 ioc->sas_discovery_quiesce_io = 0;
362 }
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530363 }
364
365 out:
366 /*
367 * Take turns polling alternate controller
368 */
369 if (ioc->alt_ioc)
370 ioc = ioc->alt_ioc;
371
372 /* rearm the timer */
Kashyap, Desai2f187862009-05-29 16:52:37 +0530373 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530374 if (ioc->reset_work_q)
375 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
376 msecs_to_jiffies(MPT_POLLING_INTERVAL));
Kashyap, Desai2f187862009-05-29 16:52:37 +0530377 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530378}
379
380
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600381/*
382 * Process turbo (context) reply...
383 */
384static void
385mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
386{
387 MPT_FRAME_HDR *mf = NULL;
388 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530389 u16 req_idx = 0;
390 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600391
Prakash, Sathya436ace72007-07-24 15:42:08 +0530392 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600393 ioc->name, pa));
394
395 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
396 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
397 req_idx = pa & 0x0000FFFF;
398 cb_idx = (pa & 0x00FF0000) >> 16;
399 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
400 break;
401 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530402 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600403 /*
404 * Blind set of mf to NULL here was fatal
405 * after lan_reply says "freeme"
406 * Fix sort of combined with an optimization here;
407 * added explicit check for case where lan_reply
408 * was just returning 1 and doing nothing else.
409 * For this case skip the callback, but set up
410 * proper mf value first here:-)
411 */
412 if ((pa & 0x58000000) == 0x58000000) {
413 req_idx = pa & 0x0000FFFF;
414 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
415 mpt_free_msg_frame(ioc, mf);
416 mb();
417 return;
418 break;
419 }
420 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
421 break;
422 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530423 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600424 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
425 break;
426 default:
427 cb_idx = 0;
428 BUG();
429 }
430
431 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530432 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600433 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600434 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700435 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600436 goto out;
437 }
438
439 if (MptCallbacks[cb_idx](ioc, mf, mr))
440 mpt_free_msg_frame(ioc, mf);
441 out:
442 mb();
443}
444
445static void
446mpt_reply(MPT_ADAPTER *ioc, u32 pa)
447{
448 MPT_FRAME_HDR *mf;
449 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530450 u16 req_idx;
451 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600452 int freeme;
453
454 u32 reply_dma_low;
455 u16 ioc_stat;
456
457 /* non-TURBO reply! Hmmm, something may be up...
458 * Newest turbo reply mechanism; get address
459 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
460 */
461
462 /* Map DMA address of reply header to cpu address.
463 * pa is 32 bits - but the dma address may be 32 or 64 bits
464 * get offset based only only the low addresses
465 */
466
467 reply_dma_low = (pa <<= 1);
468 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
469 (reply_dma_low - ioc->reply_frames_low_dma));
470
471 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
472 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
473 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
474
Prakash, Sathya436ace72007-07-24 15:42:08 +0530475 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 -0600476 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600477 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600478
479 /* Check/log IOC log info
480 */
481 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
482 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
483 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
484 if (ioc->bus_type == FC)
485 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700486 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700487 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600488 else if (ioc->bus_type == SAS)
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530489 mpt_sas_log_info(ioc, log_info, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600490 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600491
Eric Moorec6c727a2007-01-29 09:44:54 -0700492 if (ioc_stat & MPI_IOCSTATUS_MASK)
493 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600494
495 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530496 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600497 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600498 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700499 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600500 freeme = 0;
501 goto out;
502 }
503
504 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
505
506 out:
507 /* Flush (non-TURBO) reply with a WRITE! */
508 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
509
510 if (freeme)
511 mpt_free_msg_frame(ioc, mf);
512 mb();
513}
514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800516/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
518 * @irq: irq number (not used)
519 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 *
521 * This routine is registered via the request_irq() kernel API call,
522 * and handles all interrupts generated from a specific MPT adapter
523 * (also referred to as a IO Controller or IOC).
524 * This routine must clear the interrupt from the adapter and does
525 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200526 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 *
528 * This routine handles register-level access of the adapter but
529 * dispatches (calls) a protocol-specific callback routine to handle
530 * the protocol-specific details of the MPT request completion.
531 */
532static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100533mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600535 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600536 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
537
538 if (pa == 0xFFFFFFFF)
539 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
541 /*
542 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600544 do {
545 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600546 mpt_reply(ioc, pa);
547 else
548 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600549 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
550 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
552 return IRQ_HANDLED;
553}
554
555/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800556/**
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530557 * mptbase_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 * @ioc: Pointer to MPT_ADAPTER structure
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530559 * @req: Pointer to original MPT request frame
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
561 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800562 * MPT base driver's callback routine; all base driver
563 * "internal" request/reply processing is routed here.
564 * Currently used for EventNotification and EventAck handling.
565 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200566 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 * should be freed, or 0 if it shouldn't.
568 */
569static int
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530570mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530572 EventNotificationReply_t *pEventReply;
573 u8 event;
574 int evHandlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 int freereq = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530577 switch (reply->u.hdr.Function) {
578 case MPI_FUNCTION_EVENT_NOTIFICATION:
579 pEventReply = (EventNotificationReply_t *)reply;
580 evHandlers = 0;
581 ProcessEventNotification(ioc, pEventReply, &evHandlers);
582 event = le32_to_cpu(pEventReply->Event) & 0xFF;
583 if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 freereq = 0;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530585 if (event != MPI_EVENT_EVENT_CHANGE)
586 break;
587 case MPI_FUNCTION_CONFIG:
588 case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
589 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
590 if (reply) {
591 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
592 memcpy(ioc->mptbase_cmds.reply, reply,
593 min(MPT_DEFAULT_FRAME_SIZE,
594 4 * reply->u.reply.MsgLength));
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200595 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530596 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
597 ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
598 complete(&ioc->mptbase_cmds.done);
599 } else
600 freereq = 0;
601 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF)
602 freereq = 1;
603 break;
604 case MPI_FUNCTION_EVENT_ACK:
605 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
606 "EventAck reply received\n", ioc->name));
607 break;
608 default:
609 printk(MYIOC_s_ERR_FMT
610 "Unexpected msg function (=%02Xh) reply received!\n",
611 ioc->name, reply->u.hdr.Function);
612 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 }
614
615 /*
616 * Conditionally tell caller to free the original
617 * EventNotification/EventAck/unexpected request frame!
618 */
619 return freereq;
620}
621
622/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
623/**
624 * mpt_register - Register protocol-specific main callback handler.
625 * @cbfunc: callback function pointer
626 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
Randy Dunlapfc58fb12010-08-14 13:05:57 -0700627 * @func_name: call function's name
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 *
629 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800630 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 * protocol-specific driver must do this before it will be able to
632 * use any IOC resources, such as obtaining request frames.
633 *
634 * NOTES: The SCSI protocol driver currently calls this routine thrice
635 * in order to register separate callbacks; one for "normal" SCSI IO;
636 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
637 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530638 * Returns u8 valued "handle" in the range (and S.O.D. order)
639 * {N,...,7,6,5,...,1} if successful.
640 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
641 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530643u8
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530644mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass, char *func_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530646 u8 cb_idx;
647 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
649 /*
650 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
651 * (slot/handle 0 is reserved!)
652 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530653 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
654 if (MptCallbacks[cb_idx] == NULL) {
655 MptCallbacks[cb_idx] = cbfunc;
656 MptDriverClass[cb_idx] = dclass;
657 MptEvHandlers[cb_idx] = NULL;
658 last_drv_idx = cb_idx;
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530659 memcpy(MptCallbacksName[cb_idx], func_name,
660 strlen(func_name) > 50 ? 50 : strlen(func_name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 break;
662 }
663 }
664
665 return last_drv_idx;
666}
667
668/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
669/**
670 * mpt_deregister - Deregister a protocol drivers resources.
671 * @cb_idx: previously registered callback handle
672 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800673 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 * module is unloaded.
675 */
676void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530677mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600679 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 MptCallbacks[cb_idx] = NULL;
681 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
682 MptEvHandlers[cb_idx] = NULL;
683
684 last_drv_idx++;
685 }
686}
687
688/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
689/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800690 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 * @cb_idx: previously registered (via mpt_register) callback handle
692 * @ev_cbfunc: callback function
693 *
694 * This routine can be called by one or more protocol-specific drivers
695 * if/when they choose to be notified of MPT events.
696 *
697 * Returns 0 for success.
698 */
699int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530700mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600702 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 return -1;
704
705 MptEvHandlers[cb_idx] = ev_cbfunc;
706 return 0;
707}
708
709/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
710/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800711 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 * @cb_idx: previously registered callback handle
713 *
714 * Each protocol-specific driver should call this routine
715 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800716 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 */
718void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530719mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600721 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 return;
723
724 MptEvHandlers[cb_idx] = NULL;
725}
726
727/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
728/**
729 * mpt_reset_register - Register protocol-specific IOC reset handler.
730 * @cb_idx: previously registered (via mpt_register) callback handle
731 * @reset_func: reset function
732 *
733 * This routine can be called by one or more protocol-specific drivers
734 * if/when they choose to be notified of IOC resets.
735 *
736 * Returns 0 for success.
737 */
738int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530739mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530741 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 return -1;
743
744 MptResetHandlers[cb_idx] = reset_func;
745 return 0;
746}
747
748/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
749/**
750 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
751 * @cb_idx: previously registered callback handle
752 *
753 * Each protocol-specific driver should call this routine
754 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800755 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 */
757void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530758mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530760 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 return;
762
763 MptResetHandlers[cb_idx] = NULL;
764}
765
766/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
767/**
768 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800769 * @dd_cbfunc: driver callbacks struct
770 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 */
772int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530773mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774{
775 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600776 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777
Eric Moore8d6d83e2007-09-14 18:47:40 -0600778 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400779 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
781 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
782
783 /* call per pci device probe entry point */
784 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600785 id = ioc->pcidev->driver ?
786 ioc->pcidev->driver->id_table : NULL;
787 if (dd_cbfunc->probe)
788 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 }
790
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400791 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792}
793
794/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
795/**
796 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800797 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 */
799void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530800mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801{
802 struct mpt_pci_driver *dd_cbfunc;
803 MPT_ADAPTER *ioc;
804
Eric Moore8d6d83e2007-09-14 18:47:40 -0600805 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 return;
807
808 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
809
810 list_for_each_entry(ioc, &ioc_list, list) {
811 if (dd_cbfunc->remove)
812 dd_cbfunc->remove(ioc->pcidev);
813 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200814
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 MptDeviceDriverHandlers[cb_idx] = NULL;
816}
817
818
819/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
820/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800821 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530822 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 * @ioc: Pointer to MPT adapter structure
824 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800825 * Obtain an MPT request frame from the pool (of 1024) that are
826 * allocated per MPT adapter.
827 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 * Returns pointer to a MPT request frame or %NULL if none are available
829 * or IOC is not active.
830 */
831MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530832mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833{
834 MPT_FRAME_HDR *mf;
835 unsigned long flags;
836 u16 req_idx; /* Request index */
837
838 /* validate handle and ioc identifier */
839
840#ifdef MFCNT
841 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600842 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
843 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844#endif
845
846 /* If interrupts are not attached, do not return a request frame */
847 if (!ioc->active)
848 return NULL;
849
850 spin_lock_irqsave(&ioc->FreeQlock, flags);
851 if (!list_empty(&ioc->FreeQ)) {
852 int req_offset;
853
854 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
855 u.frame.linkage.list);
856 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200857 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530858 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
860 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500861 req_idx = req_offset / ioc->req_sz;
862 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600864 /* Default, will be changed if necessary in SG generation */
865 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866#ifdef MFCNT
867 ioc->mfcnt++;
868#endif
869 }
870 else
871 mf = NULL;
872 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
873
874#ifdef MFCNT
875 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600876 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
877 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
878 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 mfcounter++;
880 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600881 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
882 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883#endif
884
Eric Moore29dd3602007-09-14 18:46:51 -0600885 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
886 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 return mf;
888}
889
890/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
891/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800892 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530893 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 * @ioc: Pointer to MPT adapter structure
895 * @mf: Pointer to MPT request frame
896 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800897 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 * specific MPT adapter.
899 */
900void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530901mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902{
903 u32 mf_dma_addr;
904 int req_offset;
905 u16 req_idx; /* Request index */
906
907 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530908 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
910 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500911 req_idx = req_offset / ioc->req_sz;
912 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
914
Prakash, Sathya436ace72007-07-24 15:42:08 +0530915 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200917 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600918 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
919 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
920 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
922}
923
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530924/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800925 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530926 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530927 * @ioc: Pointer to MPT adapter structure
928 * @mf: Pointer to MPT request frame
929 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800930 * Send a protocol-specific MPT request frame to an IOC using
931 * hi-priority request queue.
932 *
933 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530934 * specific MPT adapter.
935 **/
936void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530937mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530938{
939 u32 mf_dma_addr;
940 int req_offset;
941 u16 req_idx; /* Request index */
942
943 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530944 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530945 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
946 req_idx = req_offset / ioc->req_sz;
947 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
948 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
949
950 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
951
952 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
953 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
954 ioc->name, mf_dma_addr, req_idx));
955 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
956}
957
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
959/**
960 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 * @ioc: Pointer to MPT adapter structure
962 * @mf: Pointer to MPT request frame
963 *
964 * This routine places a MPT request frame back on the MPT adapter's
965 * FreeQ.
966 */
967void
968mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
969{
970 unsigned long flags;
971
972 /* Put Request back on FreeQ! */
973 spin_lock_irqsave(&ioc->FreeQlock, flags);
Kashyap, Desai2f187862009-05-29 16:52:37 +0530974 if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf)
975 goto out;
976 /* signature to know if this mf is freed */
977 mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
979#ifdef MFCNT
980 ioc->mfcnt--;
981#endif
Kashyap, Desai2f187862009-05-29 16:52:37 +0530982 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
984}
985
986/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
987/**
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530988 * mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 * @pAddr: virtual address for SGE
990 * @flagslength: SGE flags and data transfer length
991 * @dma_addr: Physical address
992 *
993 * This routine places a MPT request frame back on the MPT adapter's
994 * FreeQ.
995 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530996static void
997mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998{
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530999 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
1000 pSge->FlagsLength = cpu_to_le32(flagslength);
1001 pSge->Address = cpu_to_le32(dma_addr);
1002}
1003
1004/**
1005 * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
1006 * @pAddr: virtual address for SGE
1007 * @flagslength: SGE flags and data transfer length
1008 * @dma_addr: Physical address
1009 *
1010 * This routine places a MPT request frame back on the MPT adapter's
1011 * FreeQ.
1012 **/
1013static void
1014mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1015{
1016 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1017 pSge->Address.Low = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301018 (lower_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301019 pSge->Address.High = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301020 (upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301021 pSge->FlagsLength = cpu_to_le32
1022 ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1023}
1024
1025/**
Randy Dunlap9cf46a32009-06-13 19:37:18 -07001026 * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr (1078 workaround).
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301027 * @pAddr: virtual address for SGE
1028 * @flagslength: SGE flags and data transfer length
1029 * @dma_addr: Physical address
1030 *
1031 * This routine places a MPT request frame back on the MPT adapter's
1032 * FreeQ.
1033 **/
1034static void
1035mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1036{
1037 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1038 u32 tmp;
1039
1040 pSge->Address.Low = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301041 (lower_32_bits(dma_addr));
1042 tmp = (u32)(upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301043
1044 /*
1045 * 1078 errata workaround for the 36GB limitation
1046 */
1047 if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {
1048 flagslength |=
1049 MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
1050 tmp |= (1<<31);
1051 if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
1052 printk(KERN_DEBUG "1078 P0M2 addressing for "
1053 "addr = 0x%llx len = %d\n",
1054 (unsigned long long)dma_addr,
1055 MPI_SGE_LENGTH(flagslength));
1056 }
1057
1058 pSge->Address.High = cpu_to_le32(tmp);
1059 pSge->FlagsLength = cpu_to_le32(
1060 (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1061}
1062
1063/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1064/**
1065 * mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
1066 * @pAddr: virtual address for SGE
1067 * @next: nextChainOffset value (u32's)
1068 * @length: length of next SGL segment
1069 * @dma_addr: Physical address
1070 *
1071 */
1072static void
1073mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1074{
1075 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
1076 pChain->Length = cpu_to_le16(length);
1077 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
1078 pChain->NextChainOffset = next;
1079 pChain->Address = cpu_to_le32(dma_addr);
1080}
1081
1082/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1083/**
1084 * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
1085 * @pAddr: virtual address for SGE
1086 * @next: nextChainOffset value (u32's)
1087 * @length: length of next SGL segment
1088 * @dma_addr: Physical address
1089 *
1090 */
1091static void
1092mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1093{
1094 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 u32 tmp = dma_addr & 0xFFFFFFFF;
1096
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301097 pChain->Length = cpu_to_le16(length);
1098 pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
1099 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301101 pChain->NextChainOffset = next;
1102
1103 pChain->Address.Low = cpu_to_le32(tmp);
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301104 tmp = (u32)(upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301105 pChain->Address.High = cpu_to_le32(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106}
1107
1108/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1109/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001110 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301111 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 * @ioc: Pointer to MPT adapter structure
1113 * @reqBytes: Size of the request in bytes
1114 * @req: Pointer to MPT request frame
1115 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1116 *
1117 * This routine is used exclusively to send MptScsiTaskMgmt
1118 * requests since they are required to be sent via doorbell handshake.
1119 *
1120 * NOTE: It is the callers responsibility to byte-swap fields in the
1121 * request which are greater than 1 byte in size.
1122 *
1123 * Returns 0 for success, non-zero for failure.
1124 */
1125int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301126mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127{
Eric Moorecd2c6192007-01-29 09:47:47 -07001128 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 u8 *req_as_bytes;
1130 int ii;
1131
1132 /* State is known to be good upon entering
1133 * this function so issue the bus reset
1134 * request.
1135 */
1136
1137 /*
1138 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1139 * setting cb_idx/req_idx. But ONLY if this request
1140 * is in proper (pre-alloc'd) request buffer range...
1141 */
1142 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1143 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1144 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1145 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301146 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 }
1148
1149 /* Make sure there are no doorbells */
1150 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001151
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1153 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1154 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1155
1156 /* Wait for IOC doorbell int */
1157 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1158 return ii;
1159 }
1160
1161 /* Read doorbell and check for active bit */
1162 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1163 return -5;
1164
Eric Moore29dd3602007-09-14 18:46:51 -06001165 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001166 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167
1168 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1169
1170 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1171 return -2;
1172 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001173
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 /* Send request via doorbell handshake */
1175 req_as_bytes = (u8 *) req;
1176 for (ii = 0; ii < reqBytes/4; ii++) {
1177 u32 word;
1178
1179 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1180 (req_as_bytes[(ii*4) + 1] << 8) |
1181 (req_as_bytes[(ii*4) + 2] << 16) |
1182 (req_as_bytes[(ii*4) + 3] << 24));
1183 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1184 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1185 r = -3;
1186 break;
1187 }
1188 }
1189
1190 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1191 r = 0;
1192 else
1193 r = -4;
1194
1195 /* Make sure there are no doorbells */
1196 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001197
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 return r;
1199}
1200
1201/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1202/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001203 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001204 * @ioc: Pointer to MPT adapter structure
1205 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001206 * @sleepFlag: Specifies whether the process can sleep
1207 *
1208 * Provides mechanism for the host driver to control the IOC's
1209 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001210 *
1211 * Access Control Value - bits[15:12]
1212 * 0h Reserved
1213 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1214 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1215 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1216 *
1217 * Returns 0 for success, non-zero for failure.
1218 */
1219
1220static int
1221mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1222{
1223 int r = 0;
1224
1225 /* return if in use */
1226 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1227 & MPI_DOORBELL_ACTIVE)
1228 return -1;
1229
1230 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1231
1232 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1233 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1234 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1235 (access_control_value<<12)));
1236
1237 /* Wait for IOC to clear Doorbell Status bit */
1238 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1239 return -2;
1240 }else
1241 return 0;
1242}
1243
1244/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1245/**
1246 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001247 * @ioc: Pointer to pointer to IOC adapter
1248 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001249 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001250 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001251 * Returns 0 for success, non-zero for failure.
1252 */
1253static int
1254mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1255{
1256 char *psge;
1257 int flags_length;
1258 u32 host_page_buffer_sz=0;
1259
1260 if(!ioc->HostPageBuffer) {
1261
1262 host_page_buffer_sz =
1263 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1264
1265 if(!host_page_buffer_sz)
1266 return 0; /* fw doesn't need any host buffers */
1267
1268 /* spin till we get enough memory */
1269 while(host_page_buffer_sz > 0) {
1270
1271 if((ioc->HostPageBuffer = pci_alloc_consistent(
1272 ioc->pcidev,
1273 host_page_buffer_sz,
1274 &ioc->HostPageBuffer_dma)) != NULL) {
1275
Prakash, Sathya436ace72007-07-24 15:42:08 +05301276 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001277 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001278 ioc->name, ioc->HostPageBuffer,
1279 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001280 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001281 ioc->alloc_total += host_page_buffer_sz;
1282 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1283 break;
1284 }
1285
1286 host_page_buffer_sz -= (4*1024);
1287 }
1288 }
1289
1290 if(!ioc->HostPageBuffer) {
1291 printk(MYIOC_s_ERR_FMT
1292 "Failed to alloc memory for host_page_buffer!\n",
1293 ioc->name);
1294 return -999;
1295 }
1296
1297 psge = (char *)&ioc_init->HostPageBufferSGE;
1298 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1299 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001300 MPI_SGE_FLAGS_HOST_TO_IOC |
1301 MPI_SGE_FLAGS_END_OF_BUFFER;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001302 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1303 flags_length |= ioc->HostPageBuffer_sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301304 ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001305 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1306
1307return 0;
1308}
1309
1310/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1311/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001312 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 * @iocid: IOC unique identifier (integer)
1314 * @iocpp: Pointer to pointer to IOC adapter
1315 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001316 * Given a unique IOC identifier, set pointer to the associated MPT
1317 * adapter structure.
1318 *
1319 * Returns iocid and sets iocpp if iocid is found.
1320 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 */
1322int
1323mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1324{
1325 MPT_ADAPTER *ioc;
1326
1327 list_for_each_entry(ioc,&ioc_list,list) {
1328 if (ioc->id == iocid) {
1329 *iocpp =ioc;
1330 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001333
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 *iocpp = NULL;
1335 return -1;
1336}
1337
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301338/**
1339 * mpt_get_product_name - returns product string
1340 * @vendor: pci vendor id
1341 * @device: pci device id
1342 * @revision: pci revision id
1343 * @prod_name: string returned
1344 *
1345 * Returns product string displayed when driver loads,
1346 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1347 *
1348 **/
1349static void
1350mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1351{
1352 char *product_str = NULL;
1353
1354 if (vendor == PCI_VENDOR_ID_BROCADE) {
1355 switch (device)
1356 {
1357 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1358 switch (revision)
1359 {
1360 case 0x00:
1361 product_str = "BRE040 A0";
1362 break;
1363 case 0x01:
1364 product_str = "BRE040 A1";
1365 break;
1366 default:
1367 product_str = "BRE040";
1368 break;
1369 }
1370 break;
1371 }
1372 goto out;
1373 }
1374
1375 switch (device)
1376 {
1377 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1378 product_str = "LSIFC909 B1";
1379 break;
1380 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1381 product_str = "LSIFC919 B0";
1382 break;
1383 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1384 product_str = "LSIFC929 B0";
1385 break;
1386 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1387 if (revision < 0x80)
1388 product_str = "LSIFC919X A0";
1389 else
1390 product_str = "LSIFC919XL A1";
1391 break;
1392 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1393 if (revision < 0x80)
1394 product_str = "LSIFC929X A0";
1395 else
1396 product_str = "LSIFC929XL A1";
1397 break;
1398 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1399 product_str = "LSIFC939X A1";
1400 break;
1401 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1402 product_str = "LSIFC949X A1";
1403 break;
1404 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1405 switch (revision)
1406 {
1407 case 0x00:
1408 product_str = "LSIFC949E A0";
1409 break;
1410 case 0x01:
1411 product_str = "LSIFC949E A1";
1412 break;
1413 default:
1414 product_str = "LSIFC949E";
1415 break;
1416 }
1417 break;
1418 case MPI_MANUFACTPAGE_DEVID_53C1030:
1419 switch (revision)
1420 {
1421 case 0x00:
1422 product_str = "LSI53C1030 A0";
1423 break;
1424 case 0x01:
1425 product_str = "LSI53C1030 B0";
1426 break;
1427 case 0x03:
1428 product_str = "LSI53C1030 B1";
1429 break;
1430 case 0x07:
1431 product_str = "LSI53C1030 B2";
1432 break;
1433 case 0x08:
1434 product_str = "LSI53C1030 C0";
1435 break;
1436 case 0x80:
1437 product_str = "LSI53C1030T A0";
1438 break;
1439 case 0x83:
1440 product_str = "LSI53C1030T A2";
1441 break;
1442 case 0x87:
1443 product_str = "LSI53C1030T A3";
1444 break;
1445 case 0xc1:
1446 product_str = "LSI53C1020A A1";
1447 break;
1448 default:
1449 product_str = "LSI53C1030";
1450 break;
1451 }
1452 break;
1453 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1454 switch (revision)
1455 {
1456 case 0x03:
1457 product_str = "LSI53C1035 A2";
1458 break;
1459 case 0x04:
1460 product_str = "LSI53C1035 B0";
1461 break;
1462 default:
1463 product_str = "LSI53C1035";
1464 break;
1465 }
1466 break;
1467 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1468 switch (revision)
1469 {
1470 case 0x00:
1471 product_str = "LSISAS1064 A1";
1472 break;
1473 case 0x01:
1474 product_str = "LSISAS1064 A2";
1475 break;
1476 case 0x02:
1477 product_str = "LSISAS1064 A3";
1478 break;
1479 case 0x03:
1480 product_str = "LSISAS1064 A4";
1481 break;
1482 default:
1483 product_str = "LSISAS1064";
1484 break;
1485 }
1486 break;
1487 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1488 switch (revision)
1489 {
1490 case 0x00:
1491 product_str = "LSISAS1064E A0";
1492 break;
1493 case 0x01:
1494 product_str = "LSISAS1064E B0";
1495 break;
1496 case 0x02:
1497 product_str = "LSISAS1064E B1";
1498 break;
1499 case 0x04:
1500 product_str = "LSISAS1064E B2";
1501 break;
1502 case 0x08:
1503 product_str = "LSISAS1064E B3";
1504 break;
1505 default:
1506 product_str = "LSISAS1064E";
1507 break;
1508 }
1509 break;
1510 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1511 switch (revision)
1512 {
1513 case 0x00:
1514 product_str = "LSISAS1068 A0";
1515 break;
1516 case 0x01:
1517 product_str = "LSISAS1068 B0";
1518 break;
1519 case 0x02:
1520 product_str = "LSISAS1068 B1";
1521 break;
1522 default:
1523 product_str = "LSISAS1068";
1524 break;
1525 }
1526 break;
1527 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1528 switch (revision)
1529 {
1530 case 0x00:
1531 product_str = "LSISAS1068E A0";
1532 break;
1533 case 0x01:
1534 product_str = "LSISAS1068E B0";
1535 break;
1536 case 0x02:
1537 product_str = "LSISAS1068E B1";
1538 break;
1539 case 0x04:
1540 product_str = "LSISAS1068E B2";
1541 break;
1542 case 0x08:
1543 product_str = "LSISAS1068E B3";
1544 break;
1545 default:
1546 product_str = "LSISAS1068E";
1547 break;
1548 }
1549 break;
1550 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1551 switch (revision)
1552 {
1553 case 0x00:
1554 product_str = "LSISAS1078 A0";
1555 break;
1556 case 0x01:
1557 product_str = "LSISAS1078 B0";
1558 break;
1559 case 0x02:
1560 product_str = "LSISAS1078 C0";
1561 break;
1562 case 0x03:
1563 product_str = "LSISAS1078 C1";
1564 break;
1565 case 0x04:
1566 product_str = "LSISAS1078 C2";
1567 break;
1568 default:
1569 product_str = "LSISAS1078";
1570 break;
1571 }
1572 break;
1573 }
1574
1575 out:
1576 if (product_str)
1577 sprintf(prod_name, "%s", product_str);
1578}
1579
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301580/**
1581 * mpt_mapresources - map in memory mapped io
1582 * @ioc: Pointer to pointer to IOC adapter
1583 *
1584 **/
1585static int
1586mpt_mapresources(MPT_ADAPTER *ioc)
1587{
1588 u8 __iomem *mem;
1589 int ii;
Pravin Bathijae46b63b2009-12-02 17:51:46 -08001590 resource_size_t mem_phys;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301591 unsigned long port;
1592 u32 msize;
1593 u32 psize;
1594 u8 revision;
1595 int r = -ENODEV;
1596 struct pci_dev *pdev;
1597
1598 pdev = ioc->pcidev;
1599 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1600 if (pci_enable_device_mem(pdev)) {
1601 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1602 "failed\n", ioc->name);
1603 return r;
1604 }
1605 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1606 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1607 "MEM failed\n", ioc->name);
1608 return r;
1609 }
1610
1611 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1612
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301613 if (sizeof(dma_addr_t) > 4) {
1614 const uint64_t required_mask = dma_get_required_mask
1615 (&pdev->dev);
1616 if (required_mask > DMA_BIT_MASK(32)
1617 && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
1618 && !pci_set_consistent_dma_mask(pdev,
1619 DMA_BIT_MASK(64))) {
1620 ioc->dma_mask = DMA_BIT_MASK(64);
1621 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1622 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1623 ioc->name));
1624 } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1625 && !pci_set_consistent_dma_mask(pdev,
1626 DMA_BIT_MASK(32))) {
1627 ioc->dma_mask = DMA_BIT_MASK(32);
1628 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1629 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1630 ioc->name));
1631 } else {
1632 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1633 ioc->name, pci_name(pdev));
Tomas Henzl653c42d2010-07-26 16:41:13 +02001634 pci_release_selected_regions(pdev, ioc->bars);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301635 return r;
1636 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301637 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301638 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1639 && !pci_set_consistent_dma_mask(pdev,
1640 DMA_BIT_MASK(32))) {
1641 ioc->dma_mask = DMA_BIT_MASK(32);
1642 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1643 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1644 ioc->name));
1645 } else {
1646 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1647 ioc->name, pci_name(pdev));
Tomas Henzl653c42d2010-07-26 16:41:13 +02001648 pci_release_selected_regions(pdev, ioc->bars);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301649 return r;
1650 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301651 }
1652
1653 mem_phys = msize = 0;
1654 port = psize = 0;
1655 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1656 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1657 if (psize)
1658 continue;
1659 /* Get I/O space! */
1660 port = pci_resource_start(pdev, ii);
1661 psize = pci_resource_len(pdev, ii);
1662 } else {
1663 if (msize)
1664 continue;
1665 /* Get memmap */
1666 mem_phys = pci_resource_start(pdev, ii);
1667 msize = pci_resource_len(pdev, ii);
1668 }
1669 }
1670 ioc->mem_size = msize;
1671
1672 mem = NULL;
1673 /* Get logical ptr for PciMem0 space */
1674 /*mem = ioremap(mem_phys, msize);*/
1675 mem = ioremap(mem_phys, msize);
1676 if (mem == NULL) {
1677 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1678 " memory!\n", ioc->name);
Tomas Henzl653c42d2010-07-26 16:41:13 +02001679 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301680 return -EINVAL;
1681 }
1682 ioc->memmap = mem;
Pravin Bathijae46b63b2009-12-02 17:51:46 -08001683 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %llx\n",
1684 ioc->name, mem, (unsigned long long)mem_phys));
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301685
1686 ioc->mem_phys = mem_phys;
1687 ioc->chip = (SYSIF_REGS __iomem *)mem;
1688
1689 /* Save Port IO values in case we need to do downloadboot */
1690 ioc->pio_mem_phys = port;
1691 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1692
1693 return 0;
1694}
1695
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001697/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001698 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001700 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 *
1702 * This routine performs all the steps necessary to bring the IOC of
1703 * a MPT adapter to a OPERATIONAL state. This includes registering
1704 * memory regions, registering the interrupt, and allocating request
1705 * and reply memory pools.
1706 *
1707 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1708 * MPT adapter.
1709 *
1710 * Returns 0 for success, non-zero for failure.
1711 *
1712 * TODO: Add support for polled controllers
1713 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001714int
1715mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716{
1717 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301718 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 u8 revision;
1721 u8 pcixcmd;
1722 static int mpt_ids = 0;
1723#ifdef CONFIG_PROC_FS
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07001724 struct proc_dir_entry *dent;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725#endif
1726
Jesper Juhl56876192007-08-10 14:50:51 -07001727 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1728 if (ioc == NULL) {
1729 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1730 return -ENOMEM;
1731 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301732
Eric Moore29dd3602007-09-14 18:46:51 -06001733 ioc->id = mpt_ids++;
1734 sprintf(ioc->name, "ioc%d", ioc->id);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301735 dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Jesper Juhl56876192007-08-10 14:50:51 -07001736
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301737 /*
1738 * set initial debug level
1739 * (refer to mptdebug.h)
1740 *
1741 */
1742 ioc->debug_level = mpt_debug_level;
1743 if (mpt_debug_level)
1744 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301745
Eric Moore29dd3602007-09-14 18:46:51 -06001746 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001747
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301748 ioc->pcidev = pdev;
1749 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001750 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 return r;
1752 }
1753
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301754 /*
1755 * Setting up proper handlers for scatter gather handling
1756 */
1757 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
1758 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
1759 ioc->add_sge = &mpt_add_sge_64bit_1078;
1760 else
1761 ioc->add_sge = &mpt_add_sge_64bit;
1762 ioc->add_chain = &mpt_add_chain_64bit;
1763 ioc->sg_addr_size = 8;
1764 } else {
1765 ioc->add_sge = &mpt_add_sge;
1766 ioc->add_chain = &mpt_add_chain;
1767 ioc->sg_addr_size = 4;
1768 }
1769 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
1770
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 ioc->alloc_total = sizeof(MPT_ADAPTER);
1772 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1773 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001774
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301776 spin_lock_init(&ioc->taskmgmt_lock);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05301777 mutex_init(&ioc->internal_cmds.mutex);
1778 init_completion(&ioc->internal_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301779 mutex_init(&ioc->mptbase_cmds.mutex);
1780 init_completion(&ioc->mptbase_cmds.done);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301781 mutex_init(&ioc->taskmgmt_cmds.mutex);
1782 init_completion(&ioc->taskmgmt_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301783
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 /* Initialize the event logging.
1785 */
1786 ioc->eventTypes = 0; /* None */
1787 ioc->eventContext = 0;
1788 ioc->eventLogSize = 0;
1789 ioc->events = NULL;
1790
1791#ifdef MFCNT
1792 ioc->mfcnt = 0;
1793#endif
1794
Kashyap, Desai2f187862009-05-29 16:52:37 +05301795 ioc->sh = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 ioc->cached_fw = NULL;
1797
Uwe Kleine-König421f91d2010-06-11 12:17:00 +02001798 /* Initialize SCSI Config Data structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001800 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801
Michael Reed05e8ec12006-01-13 14:31:54 -06001802 /* Initialize the fc rport list head.
1803 */
1804 INIT_LIST_HEAD(&ioc->fc_rports);
1805
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 /* Find lookup slot. */
1807 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001808
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301809
1810 /* Initialize workqueue */
1811 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301812
Kashyap, Desai2f187862009-05-29 16:52:37 +05301813 snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN,
Kay Sieversaab0de22008-05-02 06:02:41 +02001814 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301815 ioc->reset_work_q =
1816 create_singlethread_workqueue(ioc->reset_work_q_name);
1817 if (!ioc->reset_work_q) {
1818 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1819 ioc->name);
1820 pci_release_selected_regions(pdev, ioc->bars);
1821 kfree(ioc);
1822 return -ENOMEM;
1823 }
1824
Eric Moore29dd3602007-09-14 18:46:51 -06001825 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1826 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301828 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1829 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1830
1831 switch (pdev->device)
1832 {
1833 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1834 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1835 ioc->errata_flag_1064 = 1;
1836 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1837 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1838 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1839 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301841 break;
1842
1843 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 /* 929X Chip Fix. Set Split transactions level
1846 * for PCIX. Set MOST bits to zero.
1847 */
1848 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1849 pcixcmd &= 0x8F;
1850 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1851 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 /* 929XL Chip Fix. Set MMRBC to 0x08.
1853 */
1854 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1855 pcixcmd |= 0x08;
1856 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1857 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301859 break;
1860
1861 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 /* 919X Chip Fix. Set Split transactions level
1863 * for PCIX. Set MOST bits to zero.
1864 */
1865 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1866 pcixcmd &= 0x8F;
1867 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001868 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301869 break;
1870
1871 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 /* 1030 Chip Fix. Disable Split transactions
1873 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1874 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 if (revision < C0_1030) {
1876 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1877 pcixcmd &= 0x8F;
1878 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1879 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301880
1881 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001882 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301883 break;
1884
1885 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1886 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001887 ioc->errata_flag_1064 = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301888 ioc->bus_type = SAS;
1889 break;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301890
1891 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1892 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1893 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001894 ioc->bus_type = SAS;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301895 break;
Eric Moore87cf8982006-06-27 16:09:26 -06001896 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301898
Kashyap, Desaie3829682009-01-08 14:27:16 +05301899 switch (ioc->bus_type) {
1900
1901 case SAS:
1902 ioc->msi_enable = mpt_msi_enable_sas;
1903 break;
1904
1905 case SPI:
1906 ioc->msi_enable = mpt_msi_enable_spi;
1907 break;
1908
1909 case FC:
1910 ioc->msi_enable = mpt_msi_enable_fc;
1911 break;
1912
1913 default:
1914 ioc->msi_enable = 0;
1915 break;
1916 }
Kashyap, Desai8ce13de2010-06-17 14:35:46 +05301917
1918 ioc->fw_events_off = 1;
1919
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001920 if (ioc->errata_flag_1064)
1921 pci_disable_io_access(pdev);
1922
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 spin_lock_init(&ioc->FreeQlock);
1924
1925 /* Disable all! */
1926 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1927 ioc->active = 0;
1928 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1929
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301930 /* Set IOC ptr in the pcidev's driver data. */
1931 pci_set_drvdata(ioc->pcidev, ioc);
1932
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 /* Set lookup ptr. */
1934 list_add_tail(&ioc->list, &ioc_list);
1935
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001936 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 */
1938 mpt_detect_bound_ports(ioc, pdev);
1939
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301940 INIT_LIST_HEAD(&ioc->fw_event_list);
1941 spin_lock_init(&ioc->fw_event_lock);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301942 snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301943 ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
1944
James Bottomleyc92f2222006-03-01 09:02:49 -06001945 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1946 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001947 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1948 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001949
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001951 if (ioc->alt_ioc)
1952 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301953 iounmap(ioc->memmap);
1954 if (r != -5)
1955 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301956
1957 destroy_workqueue(ioc->reset_work_q);
1958 ioc->reset_work_q = NULL;
1959
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 kfree(ioc);
1961 pci_set_drvdata(pdev, NULL);
1962 return r;
1963 }
1964
1965 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001966 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301967 if(MptDeviceDriverHandlers[cb_idx] &&
1968 MptDeviceDriverHandlers[cb_idx]->probe) {
1969 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 }
1971 }
1972
1973#ifdef CONFIG_PROC_FS
1974 /*
1975 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1976 */
1977 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1978 if (dent) {
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07001979 proc_create_data("info", S_IRUGO, dent, &mpt_iocinfo_proc_fops, ioc);
1980 proc_create_data("summary", S_IRUGO, dent, &mpt_summary_proc_fops, ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 }
1982#endif
1983
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301984 if (!ioc->alt_ioc)
1985 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1986 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1987
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 return 0;
1989}
1990
1991/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001992/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001993 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 */
1996
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001997void
1998mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999{
2000 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2001 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302002 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302003 unsigned long flags;
2004 struct workqueue_struct *wq;
2005
2006 /*
2007 * Stop polling ioc for fault condition
2008 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302009 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302010 wq = ioc->reset_work_q;
2011 ioc->reset_work_q = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302012 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302013 cancel_delayed_work(&ioc->fault_reset_work);
2014 destroy_workqueue(wq);
2015
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05302016 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2017 wq = ioc->fw_event_q;
2018 ioc->fw_event_q = NULL;
2019 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2020 destroy_workqueue(wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021
2022 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2023 remove_proc_entry(pname, NULL);
2024 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2025 remove_proc_entry(pname, NULL);
2026 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2027 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002028
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002030 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302031 if(MptDeviceDriverHandlers[cb_idx] &&
2032 MptDeviceDriverHandlers[cb_idx]->remove) {
2033 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 }
2035 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002036
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 /* Disable interrupts! */
2038 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2039
2040 ioc->active = 0;
2041 synchronize_irq(pdev->irq);
2042
2043 /* Clear any lingering interrupt */
2044 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2045
2046 CHIPREG_READ32(&ioc->chip->IntStatus);
2047
2048 mpt_adapter_dispose(ioc);
2049
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050}
2051
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052/**************************************************************************
2053 * Power Management
2054 */
2055#ifdef CONFIG_PM
2056/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002057/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002058 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002059 * @pdev: Pointer to pci_dev structure
2060 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002062int
2063mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064{
2065 u32 device_state;
2066 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302068 device_state = pci_choose_state(pdev, state);
2069 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2070 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2071 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072
2073 /* put ioc into READY_STATE */
2074 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2075 printk(MYIOC_s_ERR_FMT
2076 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2077 }
2078
2079 /* disable interrupts */
2080 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2081 ioc->active = 0;
2082
2083 /* Clear any lingering interrupt */
2084 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2085
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302086 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002087 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302088 pci_disable_msi(ioc->pcidev);
2089 ioc->pci_irq = -1;
2090 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302092 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 return 0;
2095}
2096
2097/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002098/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002099 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002100 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002102int
2103mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104{
2105 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2106 u32 device_state = pdev->current_state;
2107 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302108 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002109
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302110 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2111 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2112 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302114 pci_set_power_state(pdev, PCI_D0);
2115 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302117 ioc->pcidev = pdev;
2118 err = mpt_mapresources(ioc);
2119 if (err)
2120 return err;
2121
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302122 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2123 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2124 ioc->add_sge = &mpt_add_sge_64bit_1078;
2125 else
2126 ioc->add_sge = &mpt_add_sge_64bit;
2127 ioc->add_chain = &mpt_add_chain_64bit;
2128 ioc->sg_addr_size = 8;
2129 } else {
2130
2131 ioc->add_sge = &mpt_add_sge;
2132 ioc->add_chain = &mpt_add_chain;
2133 ioc->sg_addr_size = 4;
2134 }
2135 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2136
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302137 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2138 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2139 CHIPREG_READ32(&ioc->chip->Doorbell));
2140
2141 /*
2142 * Errata workaround for SAS pci express:
2143 * Upon returning to the D0 state, the contents of the doorbell will be
2144 * stale data, and this will incorrectly signal to the host driver that
2145 * the firmware is ready to process mpt commands. The workaround is
2146 * to issue a diagnostic reset.
2147 */
2148 if (ioc->bus_type == SAS && (pdev->device ==
2149 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2150 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2151 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2152 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2153 ioc->name);
2154 goto out;
2155 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302156 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157
2158 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302159 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2160 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2161 CAN_SLEEP);
2162 if (recovery_state != 0)
2163 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2164 "error:[%x]\n", ioc->name, recovery_state);
2165 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302167 "pci-resume: success\n", ioc->name);
2168 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302170
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171}
2172#endif
2173
James Bottomley4ff42a62006-05-17 18:06:52 -05002174static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302175mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002176{
2177 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2178 ioc->bus_type != SPI) ||
2179 (MptDriverClass[index] == MPTFC_DRIVER &&
2180 ioc->bus_type != FC) ||
2181 (MptDriverClass[index] == MPTSAS_DRIVER &&
2182 ioc->bus_type != SAS))
2183 /* make sure we only call the relevant reset handler
2184 * for the bus */
2185 return 0;
2186 return (MptResetHandlers[index])(ioc, reset_phase);
2187}
2188
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002190/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2192 * @ioc: Pointer to MPT adapter structure
2193 * @reason: Event word / reason
2194 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2195 *
2196 * This routine performs all the steps necessary to bring the IOC
2197 * to a OPERATIONAL state.
2198 *
2199 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2200 * MPT adapter.
2201 *
2202 * Returns:
2203 * 0 for success
2204 * -1 if failed to get board READY
2205 * -2 if READY but IOCFacts Failed
2206 * -3 if READY but PrimeIOCFifos Failed
2207 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302208 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302209 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 */
2211static int
2212mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2213{
2214 int hard_reset_done = 0;
2215 int alt_ioc_ready = 0;
2216 int hard;
2217 int rc=0;
2218 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 int ret = 0;
2220 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002221 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302222 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223
Eric Moore29dd3602007-09-14 18:46:51 -06002224 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2225 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226
2227 /* Disable reply interrupts (also blocks FreeQ) */
2228 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2229 ioc->active = 0;
2230
2231 if (ioc->alt_ioc) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302232 if (ioc->alt_ioc->active ||
2233 reason == MPT_HOSTEVENT_IOC_RECOVER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 reset_alt_ioc_active = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302235 /* Disable alt-IOC's reply interrupts
2236 * (and FreeQ) for a bit
2237 **/
2238 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2239 0xFFFFFFFF);
2240 ioc->alt_ioc->active = 0;
2241 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 }
2243
2244 hard = 1;
2245 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2246 hard = 0;
2247
2248 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2249 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002250 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2251 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252
2253 if (reset_alt_ioc_active && ioc->alt_ioc) {
2254 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002255 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2256 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002257 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 ioc->alt_ioc->active = 1;
2259 }
2260
2261 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302262 printk(MYIOC_s_WARN_FMT
2263 "NOT READY WARNING!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302265 ret = -1;
2266 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 }
2268
2269 /* hard_reset_done = 0 if a soft reset was performed
2270 * and 1 if a hard reset was performed.
2271 */
2272 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2273 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2274 alt_ioc_ready = 1;
2275 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05302276 printk(MYIOC_s_WARN_FMT
2277 ": alt-ioc Not ready WARNING!\n",
2278 ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 }
2280
2281 for (ii=0; ii<5; ii++) {
2282 /* Get IOC facts! Allow 5 retries */
2283 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2284 break;
2285 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002286
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287
2288 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002289 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2290 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 ret = -2;
2292 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2293 MptDisplayIocCapabilities(ioc);
2294 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002295
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 if (alt_ioc_ready) {
2297 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302298 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302299 "Initial Alt IocFacts failed rc=%x\n",
2300 ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 /* Retry - alt IOC was initialized once
2302 */
2303 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2304 }
2305 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302306 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002307 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 alt_ioc_ready = 0;
2309 reset_alt_ioc_active = 0;
2310 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2311 MptDisplayIocCapabilities(ioc->alt_ioc);
2312 }
2313 }
2314
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302315 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2316 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2317 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2318 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2319 IORESOURCE_IO);
2320 if (pci_enable_device(ioc->pcidev))
2321 return -5;
2322 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2323 "mpt"))
2324 return -5;
2325 }
2326
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002327 /*
2328 * Device is reset now. It must have de-asserted the interrupt line
2329 * (if it was asserted) and it should be safe to register for the
2330 * interrupt now.
2331 */
2332 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2333 ioc->pci_irq = -1;
2334 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302335 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002336 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002337 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302338 else
2339 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002340 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002341 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002342 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002343 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Kashyap, Desai2f187862009-05-29 16:52:37 +05302344 "interrupt %d!\n",
2345 ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302346 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002347 pci_disable_msi(ioc->pcidev);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302348 ret = -EBUSY;
2349 goto out;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002350 }
2351 irq_allocated = 1;
2352 ioc->pci_irq = ioc->pcidev->irq;
2353 pci_set_master(ioc->pcidev); /* ?? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302354 pci_set_drvdata(ioc->pcidev, ioc);
2355 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2356 "installed at interrupt %d\n", ioc->name,
2357 ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002358 }
2359 }
2360
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 /* Prime reply & request queues!
2362 * (mucho alloc's) Must be done prior to
2363 * init as upper addresses are needed for init.
2364 * If fails, continue with alt-ioc processing
2365 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302366 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
2367 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2369 ret = -3;
2370
2371 /* May need to check/upload firmware & data here!
2372 * If fails, continue with alt-ioc processing
2373 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302374 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
2375 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2377 ret = -4;
2378// NEW!
2379 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302380 printk(MYIOC_s_WARN_FMT
2381 ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002382 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 alt_ioc_ready = 0;
2384 reset_alt_ioc_active = 0;
2385 }
2386
2387 if (alt_ioc_ready) {
2388 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2389 alt_ioc_ready = 0;
2390 reset_alt_ioc_active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302391 printk(MYIOC_s_WARN_FMT
2392 ": alt-ioc: (%d) init failure WARNING!\n",
2393 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 }
2395 }
2396
2397 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2398 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302399 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002400 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401
2402 /* Controller is not operational, cannot do upload
2403 */
2404 if (ret == 0) {
2405 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002406 if (rc == 0) {
2407 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2408 /*
2409 * Maintain only one pointer to FW memory
2410 * so there will not be two attempt to
2411 * downloadboot onboard dual function
2412 * chips (mpt_adapter_disable,
2413 * mpt_diag_reset)
2414 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302415 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002416 "mpt_upload: alt_%s has cached_fw=%p \n",
2417 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302418 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002419 }
2420 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002421 printk(MYIOC_s_WARN_FMT
2422 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302423 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002424 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 }
2426 }
2427 }
2428
Kashyap, Desaifd761752009-05-29 16:39:06 +05302429 /* Enable MPT base driver management of EventNotification
2430 * and EventAck handling.
2431 */
2432 if ((ret == 0) && (!ioc->facts.EventState)) {
2433 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2434 "SendEventNotification\n",
2435 ioc->name));
2436 ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
2437 }
2438
2439 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2440 rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
2441
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 if (ret == 0) {
2443 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002444 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 ioc->active = 1;
2446 }
Kashyap, Desaifd761752009-05-29 16:39:06 +05302447 if (rc == 0) { /* alt ioc */
2448 if (reset_alt_ioc_active && ioc->alt_ioc) {
2449 /* (re)Enable alt-IOC! (reply interrupt) */
2450 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
2451 "reply irq re-enabled\n",
2452 ioc->alt_ioc->name));
2453 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2454 MPI_HIM_DIM);
2455 ioc->alt_ioc->active = 1;
2456 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 }
2458
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002460 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2462 * recursive scenario; GetLanConfigPages times out, timer expired
2463 * routine calls HardResetHandler, which calls into here again,
2464 * and we try GetLanConfigPages again...
2465 */
2466 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002467
2468 /*
Uwe Kleine-König421f91d2010-06-11 12:17:00 +02002469 * Initialize link list for inactive raid volumes.
Eric Mooreb506ade2007-01-29 09:45:37 -07002470 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002471 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002472 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2473
Kashyap, Desai2f187862009-05-29 16:52:37 +05302474 switch (ioc->bus_type) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002475
Kashyap, Desai2f187862009-05-29 16:52:37 +05302476 case SAS:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002477 /* clear persistency table */
2478 if(ioc->facts.IOCExceptions &
2479 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2480 ret = mptbase_sas_persist_operation(ioc,
2481 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2482 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002483 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002484 }
2485
2486 /* Find IM volumes
2487 */
2488 mpt_findImVolumes(ioc);
2489
Kashyap, Desai2f187862009-05-29 16:52:37 +05302490 /* Check, and possibly reset, the coalescing value
2491 */
2492 mpt_read_ioc_pg_1(ioc);
2493
2494 break;
2495
2496 case FC:
2497 if ((ioc->pfacts[0].ProtocolFlags &
2498 MPI_PORTFACTS_PROTOCOL_LAN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2500 /*
2501 * Pre-fetch the ports LAN MAC address!
2502 * (LANPage1_t stuff)
2503 */
2504 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302505 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2506 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302507 "LanAddr = %02X:%02X:%02X"
2508 ":%02X:%02X:%02X\n",
2509 ioc->name, a[5], a[4],
2510 a[3], a[2], a[1], a[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302512 break;
2513
2514 case SPI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 /* Get NVRAM and adapter maximums from SPP 0 and 2
2516 */
2517 mpt_GetScsiPortSettings(ioc, 0);
2518
2519 /* Get version and length of SDP 1
2520 */
2521 mpt_readScsiDevicePageHeaders(ioc, 0);
2522
2523 /* Find IM volumes
2524 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002525 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 mpt_findImVolumes(ioc);
2527
2528 /* Check, and possibly reset, the coalescing value
2529 */
2530 mpt_read_ioc_pg_1(ioc);
2531
2532 mpt_read_ioc_pg_4(ioc);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302533
2534 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 }
2536
2537 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302538 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 }
2540
Eric Moore0ccdb002006-07-11 17:33:13 -06002541 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002542 if ((ret != 0) && irq_allocated) {
2543 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302544 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002545 pci_disable_msi(ioc->pcidev);
2546 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 return ret;
2548}
2549
2550/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002551/**
2552 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 * @ioc: Pointer to MPT adapter structure
2554 * @pdev: Pointer to (struct pci_dev) structure
2555 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002556 * Search for PCI bus/dev_function which matches
2557 * PCI bus/dev_function (+/-1) for newly discovered 929,
2558 * 929X, 1030 or 1035.
2559 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2561 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2562 */
2563static void
2564mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2565{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002566 struct pci_dev *peer=NULL;
2567 unsigned int slot = PCI_SLOT(pdev->devfn);
2568 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 MPT_ADAPTER *ioc_srch;
2570
Prakash, Sathya436ace72007-07-24 15:42:08 +05302571 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002572 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002573 ioc->name, pci_name(pdev), pdev->bus->number,
2574 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002575
2576 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2577 if (!peer) {
2578 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2579 if (!peer)
2580 return;
2581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582
2583 list_for_each_entry(ioc_srch, &ioc_list, list) {
2584 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002585 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 /* Paranoia checks */
2587 if (ioc->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302588 printk(MYIOC_s_WARN_FMT
2589 "Oops, already bound (%s <==> %s)!\n",
2590 ioc->name, ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 break;
2592 } else if (ioc_srch->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302593 printk(MYIOC_s_WARN_FMT
2594 "Oops, already bound (%s <==> %s)!\n",
2595 ioc_srch->name, ioc_srch->name,
2596 ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 break;
2598 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302599 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2600 "FOUND! binding %s <==> %s\n",
2601 ioc->name, ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 ioc_srch->alt_ioc = ioc;
2603 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 }
2605 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002606 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607}
2608
2609/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002610/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002612 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 */
2614static void
2615mpt_adapter_disable(MPT_ADAPTER *ioc)
2616{
2617 int sz;
2618 int ret;
2619
2620 if (ioc->cached_fw != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302621 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2622 "%s: Pushing FW onto adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302623 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2624 ioc->cached_fw, CAN_SLEEP)) < 0) {
2625 printk(MYIOC_s_WARN_FMT
2626 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002627 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 }
2629 }
2630
Kashyap, Desai71278192009-05-29 16:53:14 +05302631 /*
2632 * Put the controller into ready state (if its not already)
2633 */
2634 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {
2635 if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
2636 CAN_SLEEP)) {
2637 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)
2638 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit "
2639 "reset failed to put ioc in ready state!\n",
2640 ioc->name, __func__);
2641 } else
2642 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset "
2643 "failed!\n", ioc->name, __func__);
2644 }
2645
2646
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 /* Disable adapter interrupts! */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302648 synchronize_irq(ioc->pcidev->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2650 ioc->active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302651
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 /* Clear any lingering interrupt */
2653 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302654 CHIPREG_READ32(&ioc->chip->IntStatus);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655
2656 if (ioc->alloc != NULL) {
2657 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002658 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2659 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 pci_free_consistent(ioc->pcidev, sz,
2661 ioc->alloc, ioc->alloc_dma);
2662 ioc->reply_frames = NULL;
2663 ioc->req_frames = NULL;
2664 ioc->alloc = NULL;
2665 ioc->alloc_total -= sz;
2666 }
2667
2668 if (ioc->sense_buf_pool != NULL) {
2669 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2670 pci_free_consistent(ioc->pcidev, sz,
2671 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2672 ioc->sense_buf_pool = NULL;
2673 ioc->alloc_total -= sz;
2674 }
2675
2676 if (ioc->events != NULL){
2677 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2678 kfree(ioc->events);
2679 ioc->events = NULL;
2680 ioc->alloc_total -= sz;
2681 }
2682
Prakash, Sathya984621b2008-01-11 14:42:17 +05302683 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002685 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002686 mpt_inactive_raid_list_free(ioc);
2687 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002688 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002689 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002690 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691
2692 if (ioc->spi_data.pIocPg4 != NULL) {
2693 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302694 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 ioc->spi_data.pIocPg4,
2696 ioc->spi_data.IocPg4_dma);
2697 ioc->spi_data.pIocPg4 = NULL;
2698 ioc->alloc_total -= sz;
2699 }
2700
2701 if (ioc->ReqToChain != NULL) {
2702 kfree(ioc->ReqToChain);
2703 kfree(ioc->RequestNB);
2704 ioc->ReqToChain = NULL;
2705 }
2706
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002707 kfree(ioc->ChainToChain);
2708 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002709
2710 if (ioc->HostPageBuffer != NULL) {
2711 if((ret = mpt_host_page_access_control(ioc,
2712 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002713 printk(MYIOC_s_ERR_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302714 ": %s: host page buffers free failed (%d)!\n",
2715 ioc->name, __func__, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002716 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302717 dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2718 "HostPageBuffer free @ %p, sz=%d bytes\n",
2719 ioc->name, ioc->HostPageBuffer,
2720 ioc->HostPageBuffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002721 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002722 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002723 ioc->HostPageBuffer = NULL;
2724 ioc->HostPageBuffer_sz = 0;
2725 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2726 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727
Kashyap, Desai2f187862009-05-29 16:52:37 +05302728 pci_set_drvdata(ioc->pcidev, NULL);
2729}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002731/**
2732 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 * @ioc: Pointer to MPT adapter structure
2734 *
2735 * This routine unregisters h/w resources and frees all alloc'd memory
2736 * associated with a MPT adapter structure.
2737 */
2738static void
2739mpt_adapter_dispose(MPT_ADAPTER *ioc)
2740{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002741 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002743 if (ioc == NULL)
2744 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002746 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002748 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002750 if (ioc->pci_irq != -1) {
2751 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302752 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002753 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002754 ioc->pci_irq = -1;
2755 }
2756
2757 if (ioc->memmap != NULL) {
2758 iounmap(ioc->memmap);
2759 ioc->memmap = NULL;
2760 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302762 pci_disable_device(ioc->pcidev);
2763 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2764
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002766 if (ioc->mtrr_reg > 0) {
2767 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002768 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002769 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770#endif
2771
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002772 /* Zap the adapter lookup ptr! */
2773 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002775 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002776 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2777 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002778
2779 if (ioc->alt_ioc)
2780 ioc->alt_ioc->alt_ioc = NULL;
2781
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002782 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783}
2784
2785/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002786/**
2787 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 * @ioc: Pointer to MPT adapter structure
2789 */
2790static void
2791MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2792{
2793 int i = 0;
2794
2795 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302796 if (ioc->prod_name)
2797 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 printk("Capabilities={");
2799
2800 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2801 printk("Initiator");
2802 i++;
2803 }
2804
2805 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2806 printk("%sTarget", i ? "," : "");
2807 i++;
2808 }
2809
2810 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2811 printk("%sLAN", i ? "," : "");
2812 i++;
2813 }
2814
2815#if 0
2816 /*
2817 * This would probably evoke more questions than it's worth
2818 */
2819 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2820 printk("%sLogBusAddr", i ? "," : "");
2821 i++;
2822 }
2823#endif
2824
2825 printk("}\n");
2826}
2827
2828/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002829/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2831 * @ioc: Pointer to MPT_ADAPTER structure
2832 * @force: Force hard KickStart of IOC
2833 * @sleepFlag: Specifies whether the process can sleep
2834 *
2835 * Returns:
2836 * 1 - DIAG reset and READY
2837 * 0 - READY initially OR soft reset and READY
2838 * -1 - Any failure on KickStart
2839 * -2 - Msg Unit Reset Failed
2840 * -3 - IO Unit Reset Failed
2841 * -4 - IOC owned by a PEER
2842 */
2843static int
2844MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2845{
2846 u32 ioc_state;
2847 int statefault = 0;
2848 int cntdn;
2849 int hard_reset_done = 0;
2850 int r;
2851 int ii;
2852 int whoinit;
2853
2854 /* Get current [raw] IOC state */
2855 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002856 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857
2858 /*
2859 * Check to see if IOC got left/stuck in doorbell handshake
2860 * grip of death. If so, hard reset the IOC.
2861 */
2862 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2863 statefault = 1;
2864 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2865 ioc->name);
2866 }
2867
2868 /* Is it already READY? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302869 if (!statefault &&
2870 ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) {
2871 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2872 "IOC is in READY state\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 return 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875
2876 /*
2877 * Check to see if IOC is in FAULT state.
2878 */
2879 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2880 statefault = 2;
2881 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002882 ioc->name);
2883 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2884 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 }
2886
2887 /*
2888 * Hmmm... Did it get left operational?
2889 */
2890 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302891 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 ioc->name));
2893
2894 /* Check WhoInit.
2895 * If PCI Peer, exit.
2896 * Else, if no fault conditions are present, issue a MessageUnitReset
2897 * Else, fall through to KickStart case
2898 */
2899 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002900 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2901 "whoinit 0x%x statefault %d force %d\n",
2902 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 if (whoinit == MPI_WHOINIT_PCI_PEER)
2904 return -4;
2905 else {
2906 if ((statefault == 0 ) && (force == 0)) {
2907 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2908 return 0;
2909 }
2910 statefault = 3;
2911 }
2912 }
2913
2914 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2915 if (hard_reset_done < 0)
2916 return -1;
2917
2918 /*
2919 * Loop here waiting for IOC to come READY.
2920 */
2921 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002922 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923
2924 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2925 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2926 /*
2927 * BIOS or previous driver load left IOC in OP state.
2928 * Reset messaging FIFOs.
2929 */
2930 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2931 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2932 return -2;
2933 }
2934 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2935 /*
2936 * Something is wrong. Try to get IOC back
2937 * to a known state.
2938 */
2939 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2940 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2941 return -3;
2942 }
2943 }
2944
2945 ii++; cntdn--;
2946 if (!cntdn) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302947 printk(MYIOC_s_ERR_FMT
2948 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
2949 ioc->name, ioc_state, (int)((ii+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 return -ETIME;
2951 }
2952
2953 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002954 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 } else {
2956 mdelay (1); /* 1 msec delay */
2957 }
2958
2959 }
2960
2961 if (statefault < 3) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302962 printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name,
2963 statefault == 1 ? "stuck handshake" : "IOC FAULT");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 }
2965
2966 return hard_reset_done;
2967}
2968
2969/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002970/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 * mpt_GetIocState - Get the current state of a MPT adapter.
2972 * @ioc: Pointer to MPT_ADAPTER structure
2973 * @cooked: Request raw or cooked IOC state
2974 *
2975 * Returns all IOC Doorbell register bits if cooked==0, else just the
2976 * Doorbell bits in MPI_IOC_STATE_MASK.
2977 */
2978u32
2979mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2980{
2981 u32 s, sc;
2982
2983 /* Get! */
2984 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 sc = s & MPI_IOC_STATE_MASK;
2986
2987 /* Save! */
2988 ioc->last_state = sc;
2989
2990 return cooked ? sc : s;
2991}
2992
2993/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002994/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 * GetIocFacts - Send IOCFacts request to MPT adapter.
2996 * @ioc: Pointer to MPT_ADAPTER structure
2997 * @sleepFlag: Specifies whether the process can sleep
2998 * @reason: If recovery, only update facts.
2999 *
3000 * Returns 0 for success, non-zero for failure.
3001 */
3002static int
3003GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
3004{
3005 IOCFacts_t get_facts;
3006 IOCFactsReply_t *facts;
3007 int r;
3008 int req_sz;
3009 int reply_sz;
3010 int sz;
3011 u32 status, vv;
3012 u8 shiftFactor=1;
3013
3014 /* IOC *must* NOT be in RESET state! */
3015 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303016 printk(KERN_ERR MYNAM
3017 ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
3018 ioc->name, ioc->last_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019 return -44;
3020 }
3021
3022 facts = &ioc->facts;
3023
3024 /* Destination (reply area)... */
3025 reply_sz = sizeof(*facts);
3026 memset(facts, 0, reply_sz);
3027
3028 /* Request area (get_facts on the stack right now!) */
3029 req_sz = sizeof(get_facts);
3030 memset(&get_facts, 0, req_sz);
3031
3032 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
3033 /* Assert: All other get_facts fields are zero! */
3034
Prakash, Sathya436ace72007-07-24 15:42:08 +05303035 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003036 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 ioc->name, req_sz, reply_sz));
3038
3039 /* No non-zero fields in the get_facts request are greater than
3040 * 1 byte in size, so we can just fire it off as is.
3041 */
3042 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3043 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3044 if (r != 0)
3045 return r;
3046
3047 /*
3048 * Now byte swap (GRRR) the necessary fields before any further
3049 * inspection of reply contents.
3050 *
3051 * But need to do some sanity checks on MsgLength (byte) field
3052 * to make sure we don't zero IOC's req_sz!
3053 */
3054 /* Did we get a valid reply? */
3055 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3056 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3057 /*
3058 * If not been here, done that, save off first WhoInit value
3059 */
3060 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3061 ioc->FirstWhoInit = facts->WhoInit;
3062 }
3063
3064 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3065 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3066 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3067 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3068 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003069 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 /* CHECKME! IOCStatus, IOCLogInfo */
3071
3072 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3073 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3074
3075 /*
3076 * FC f/w version changed between 1.1 and 1.2
3077 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3078 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3079 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303080 if (facts->MsgVersion < MPI_VERSION_01_02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 /*
3082 * Handle old FC f/w style, convert to new...
3083 */
3084 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3085 facts->FWVersion.Word =
3086 ((oldv<<12) & 0xFF000000) |
3087 ((oldv<<8) & 0x000FFF00);
3088 } else
3089 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3090
3091 facts->ProductID = le16_to_cpu(facts->ProductID);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303092
Eric Mooreb506ade2007-01-29 09:45:37 -07003093 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3094 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3095 ioc->ir_firmware = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303096
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 facts->CurrentHostMfaHighAddr =
3098 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3099 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3100 facts->CurrentSenseBufferHighAddr =
3101 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3102 facts->CurReplyFrameSize =
3103 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003104 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105
3106 /*
3107 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3108 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3109 * to 14 in MPI-1.01.0x.
3110 */
3111 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
Kashyap, Desai2f187862009-05-29 16:52:37 +05303112 facts->MsgVersion > MPI_VERSION_01_00) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3114 }
3115
3116 sz = facts->FWImageSize;
3117 if ( sz & 0x01 )
3118 sz += 1;
3119 if ( sz & 0x02 )
3120 sz += 2;
3121 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003122
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 if (!facts->RequestFrameSize) {
3124 /* Something is wrong! */
3125 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3126 ioc->name);
3127 return -55;
3128 }
3129
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003130 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 vv = ((63 / (sz * 4)) + 1) & 0x03;
3132 ioc->NB_for_64_byte_frame = vv;
3133 while ( sz )
3134 {
3135 shiftFactor++;
3136 sz = sz >> 1;
3137 }
3138 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303139 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003140 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3141 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003142
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3144 /*
3145 * Set values for this IOC's request & reply frame sizes,
3146 * and request & reply queue depths...
3147 */
3148 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3149 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3150 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3151 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3152
Prakash, Sathya436ace72007-07-24 15:42:08 +05303153 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303155 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 ioc->name, ioc->req_sz, ioc->req_depth));
3157
3158 /* Get port facts! */
3159 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3160 return r;
3161 }
3162 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003163 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3165 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3166 RequestFrameSize)/sizeof(u32)));
3167 return -66;
3168 }
3169
3170 return 0;
3171}
3172
3173/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003174/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175 * GetPortFacts - Send PortFacts request to MPT adapter.
3176 * @ioc: Pointer to MPT_ADAPTER structure
3177 * @portnum: Port number
3178 * @sleepFlag: Specifies whether the process can sleep
3179 *
3180 * Returns 0 for success, non-zero for failure.
3181 */
3182static int
3183GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3184{
3185 PortFacts_t get_pfacts;
3186 PortFactsReply_t *pfacts;
3187 int ii;
3188 int req_sz;
3189 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003190 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191
3192 /* IOC *must* NOT be in RESET state! */
3193 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003194 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3195 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 return -4;
3197 }
3198
3199 pfacts = &ioc->pfacts[portnum];
3200
3201 /* Destination (reply area)... */
3202 reply_sz = sizeof(*pfacts);
3203 memset(pfacts, 0, reply_sz);
3204
3205 /* Request area (get_pfacts on the stack right now!) */
3206 req_sz = sizeof(get_pfacts);
3207 memset(&get_pfacts, 0, req_sz);
3208
3209 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3210 get_pfacts.PortNumber = portnum;
3211 /* Assert: All other get_pfacts fields are zero! */
3212
Prakash, Sathya436ace72007-07-24 15:42:08 +05303213 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 ioc->name, portnum));
3215
3216 /* No non-zero fields in the get_pfacts request are greater than
3217 * 1 byte in size, so we can just fire it off as is.
3218 */
3219 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3220 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3221 if (ii != 0)
3222 return ii;
3223
3224 /* Did we get a valid reply? */
3225
3226 /* Now byte swap the necessary fields in the response. */
3227 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3228 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3229 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3230 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3231 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3232 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3233 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3234 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3235 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3236
Eric Moore793955f2007-01-29 09:42:20 -07003237 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3238 pfacts->MaxDevices;
3239 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3240 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3241
3242 /*
3243 * Place all the devices on channels
3244 *
3245 * (for debuging)
3246 */
3247 if (mpt_channel_mapping) {
3248 ioc->devices_per_bus = 1;
3249 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3250 }
3251
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252 return 0;
3253}
3254
3255/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003256/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257 * SendIocInit - Send IOCInit request to MPT adapter.
3258 * @ioc: Pointer to MPT_ADAPTER structure
3259 * @sleepFlag: Specifies whether the process can sleep
3260 *
3261 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3262 *
3263 * Returns 0 for success, non-zero for failure.
3264 */
3265static int
3266SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3267{
3268 IOCInit_t ioc_init;
3269 MPIDefaultReply_t init_reply;
3270 u32 state;
3271 int r;
3272 int count;
3273 int cntdn;
3274
3275 memset(&ioc_init, 0, sizeof(ioc_init));
3276 memset(&init_reply, 0, sizeof(init_reply));
3277
3278 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3279 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3280
3281 /* If we are in a recovery mode and we uploaded the FW image,
3282 * then this pointer is not NULL. Skip the upload a second time.
3283 * Set this flag if cached_fw set for either IOC.
3284 */
3285 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3286 ioc->upload_fw = 1;
3287 else
3288 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303289 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3291
Eric Moore793955f2007-01-29 09:42:20 -07003292 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3293 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303294
Prakash, Sathya436ace72007-07-24 15:42:08 +05303295 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003296 ioc->name, ioc->facts.MsgVersion));
3297 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3298 // set MsgVersion and HeaderVersion host driver was built with
3299 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3300 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003302 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3303 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3304 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3305 return -99;
3306 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3308
Kashyap, Desai2f187862009-05-29 16:52:37 +05303309 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 /* Save the upper 32-bits of the request
3311 * (reply) and sense buffers.
3312 */
3313 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3314 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3315 } else {
3316 /* Force 32-bit addressing */
3317 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3318 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3319 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003320
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3322 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003323 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3324 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325
Prakash, Sathya436ace72007-07-24 15:42:08 +05303326 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 ioc->name, &ioc_init));
3328
3329 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3330 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003331 if (r != 0) {
3332 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003334 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335
3336 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003337 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338 */
3339
Prakash, Sathya436ace72007-07-24 15:42:08 +05303340 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003342
3343 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3344 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003346 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347
3348 /* YIKES! SUPER IMPORTANT!!!
3349 * Poll IocState until _OPERATIONAL while IOC is doing
3350 * LoopInit and TargetDiscovery!
3351 */
3352 count = 0;
3353 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3354 state = mpt_GetIocState(ioc, 1);
3355 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3356 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003357 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 } else {
3359 mdelay(1);
3360 }
3361
3362 if (!cntdn) {
3363 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3364 ioc->name, (int)((count+5)/HZ));
3365 return -9;
3366 }
3367
3368 state = mpt_GetIocState(ioc, 1);
3369 count++;
3370 }
Eric Moore29dd3602007-09-14 18:46:51 -06003371 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 ioc->name, count));
3373
Eric Mooreba856d32006-07-11 17:34:01 -06003374 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 return r;
3376}
3377
3378/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003379/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 * SendPortEnable - Send PortEnable request to MPT adapter port.
3381 * @ioc: Pointer to MPT_ADAPTER structure
3382 * @portnum: Port number to enable
3383 * @sleepFlag: Specifies whether the process can sleep
3384 *
3385 * Send PortEnable to bring IOC to OPERATIONAL state.
3386 *
3387 * Returns 0 for success, non-zero for failure.
3388 */
3389static int
3390SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3391{
3392 PortEnable_t port_enable;
3393 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003394 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395 int req_sz;
3396 int reply_sz;
3397
3398 /* Destination... */
3399 reply_sz = sizeof(MPIDefaultReply_t);
3400 memset(&reply_buf, 0, reply_sz);
3401
3402 req_sz = sizeof(PortEnable_t);
3403 memset(&port_enable, 0, req_sz);
3404
3405 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3406 port_enable.PortNumber = portnum;
3407/* port_enable.ChainOffset = 0; */
3408/* port_enable.MsgFlags = 0; */
3409/* port_enable.MsgContext = 0; */
3410
Prakash, Sathya436ace72007-07-24 15:42:08 +05303411 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 ioc->name, portnum, &port_enable));
3413
3414 /* RAID FW may take a long time to enable
3415 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003416 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003417 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3418 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3419 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003420 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003421 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3422 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3423 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003425 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426}
3427
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003428/**
3429 * mpt_alloc_fw_memory - allocate firmware memory
3430 * @ioc: Pointer to MPT_ADAPTER structure
3431 * @size: total FW bytes
3432 *
3433 * If memory has already been allocated, the same (cached) value
3434 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303435 *
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003436 * Return 0 if successful, or non-zero for failure
Prakash, Sathya984621b2008-01-11 14:42:17 +05303437 **/
3438int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3440{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303441 int rc;
3442
3443 if (ioc->cached_fw) {
3444 rc = 0; /* use already allocated memory */
3445 goto out;
3446 }
3447 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3449 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303450 rc = 0;
3451 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303453 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3454 if (!ioc->cached_fw) {
3455 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3456 ioc->name);
3457 rc = -1;
3458 } else {
3459 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3460 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3461 ioc->alloc_total += size;
3462 rc = 0;
3463 }
3464 out:
3465 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303467
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003468/**
3469 * mpt_free_fw_memory - free firmware memory
3470 * @ioc: Pointer to MPT_ADAPTER structure
3471 *
3472 * If alt_img is NULL, delete from ioc structure.
3473 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303474 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475void
3476mpt_free_fw_memory(MPT_ADAPTER *ioc)
3477{
3478 int sz;
3479
Prakash, Sathya984621b2008-01-11 14:42:17 +05303480 if (!ioc->cached_fw)
3481 return;
3482
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303484 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3485 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003486 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303487 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489}
3490
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003492/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3494 * @ioc: Pointer to MPT_ADAPTER structure
3495 * @sleepFlag: Specifies whether the process can sleep
3496 *
3497 * Returns 0 for success, >0 for handshake failure
3498 * <0 for fw upload failure.
3499 *
3500 * Remark: If bound IOC and a successful FWUpload was performed
3501 * on the bound IOC, the second image is discarded
3502 * and memory is free'd. Both channels must upload to prevent
3503 * IOC from running in degraded mode.
3504 */
3505static int
3506mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3507{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508 u8 reply[sizeof(FWUploadReply_t)];
3509 FWUpload_t *prequest;
3510 FWUploadReply_t *preply;
3511 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 u32 flagsLength;
3513 int ii, sz, reply_sz;
3514 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303515 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 /* If the image size is 0, we are done.
3517 */
3518 if ((sz = ioc->facts.FWImageSize) == 0)
3519 return 0;
3520
Prakash, Sathya984621b2008-01-11 14:42:17 +05303521 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3522 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523
Eric Moore29dd3602007-09-14 18:46:51 -06003524 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3525 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003526
Eric Moorebc6e0892007-09-29 10:16:28 -06003527 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3528 kzalloc(ioc->req_sz, GFP_KERNEL);
3529 if (!prequest) {
3530 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3531 "while allocating memory \n", ioc->name));
3532 mpt_free_fw_memory(ioc);
3533 return -ENOMEM;
3534 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535
Eric Moorebc6e0892007-09-29 10:16:28 -06003536 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537
3538 reply_sz = sizeof(reply);
3539 memset(preply, 0, reply_sz);
3540
3541 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3542 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3543
3544 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3545 ptcsge->DetailsLength = 12;
3546 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3547 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003548 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303551 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3552 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3553 ioc->SGE_size;
3554 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3555 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3556 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003557 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303559 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3560 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561
Kashyap, Desai2f187862009-05-29 16:52:37 +05303562 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
3563 "rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564
3565 cmdStatus = -EFAULT;
3566 if (ii == 0) {
3567 /* Handshake transfer was complete and successful.
3568 * Check the Reply Frame.
3569 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303570 int status;
3571 status = le16_to_cpu(preply->IOCStatus) &
3572 MPI_IOCSTATUS_MASK;
3573 if (status == MPI_IOCSTATUS_SUCCESS &&
3574 ioc->facts.FWImageSize ==
3575 le32_to_cpu(preply->ActualImageSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576 cmdStatus = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303578 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 ioc->name, cmdStatus));
3580
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003581
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 if (cmdStatus) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303583 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
3584 "freeing image \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 mpt_free_fw_memory(ioc);
3586 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003587 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588
3589 return cmdStatus;
3590}
3591
3592/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003593/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 * mpt_downloadboot - DownloadBoot code
3595 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003596 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 * @sleepFlag: Specifies whether the process can sleep
3598 *
3599 * FwDownloadBoot requires Programmed IO access.
3600 *
3601 * Returns 0 for success
3602 * -1 FW Image size is 0
3603 * -2 No valid cached_fw Pointer
3604 * <0 for fw upload failure.
3605 */
3606static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003607mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 MpiExtImageHeader_t *pExtImage;
3610 u32 fwSize;
3611 u32 diag0val;
3612 int count;
3613 u32 *ptrFw;
3614 u32 diagRwData;
3615 u32 nextImage;
3616 u32 load_addr;
3617 u32 ioc_state=0;
3618
Prakash, Sathya436ace72007-07-24 15:42:08 +05303619 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003620 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003621
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3623 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3624 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3625 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3626 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3627 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3628
3629 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3630
3631 /* wait 1 msec */
3632 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003633 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 } else {
3635 mdelay (1);
3636 }
3637
3638 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3639 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3640
3641 for (count = 0; count < 30; count ++) {
3642 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3643 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303644 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 ioc->name, count));
3646 break;
3647 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003648 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003650 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003652 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 }
3654 }
3655
3656 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303657 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003658 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 ioc->name, diag0val));
3660 return -3;
3661 }
3662
3663 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3664 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3665 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3666 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3667 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3668 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3669
3670 /* Set the DiagRwEn and Disable ARM bits */
3671 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3672
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 fwSize = (pFwHeader->ImageSize + 3)/4;
3674 ptrFw = (u32 *) pFwHeader;
3675
3676 /* Write the LoadStartAddress to the DiagRw Address Register
3677 * using Programmed IO
3678 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003679 if (ioc->errata_flag_1064)
3680 pci_enable_io_access(ioc->pcidev);
3681
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303683 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 ioc->name, pFwHeader->LoadStartAddress));
3685
Prakash, Sathya436ace72007-07-24 15:42:08 +05303686 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 ioc->name, fwSize*4, ptrFw));
3688 while (fwSize--) {
3689 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3690 }
3691
3692 nextImage = pFwHeader->NextImageHeaderOffset;
3693 while (nextImage) {
3694 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3695
3696 load_addr = pExtImage->LoadStartAddress;
3697
3698 fwSize = (pExtImage->ImageSize + 3) >> 2;
3699 ptrFw = (u32 *)pExtImage;
3700
Prakash, Sathya436ace72007-07-24 15:42:08 +05303701 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 +02003702 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3704
3705 while (fwSize--) {
3706 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3707 }
3708 nextImage = pExtImage->NextImageHeaderOffset;
3709 }
3710
3711 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303712 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3714
3715 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303716 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3718
3719 /* Clear the internal flash bad bit - autoincrementing register,
3720 * so must do two writes.
3721 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003722 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003723 /*
3724 * 1030 and 1035 H/W errata, workaround to access
3725 * the ClearFlashBadSignatureBit
3726 */
3727 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3728 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3729 diagRwData |= 0x40000000;
3730 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3731 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3732
3733 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3734 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3735 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3736 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3737
3738 /* wait 1 msec */
3739 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003740 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003741 } else {
3742 mdelay (1);
3743 }
3744 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003746 if (ioc->errata_flag_1064)
3747 pci_disable_io_access(ioc->pcidev);
3748
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303750 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003751 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003753 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303754 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755 ioc->name, diag0val));
3756 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3757
3758 /* Write 0xFF to reset the sequencer */
3759 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3760
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003761 if (ioc->bus_type == SAS) {
3762 ioc_state = mpt_GetIocState(ioc, 0);
3763 if ( (GetIocFacts(ioc, sleepFlag,
3764 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303765 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003766 ioc->name, ioc_state));
3767 return -EFAULT;
3768 }
3769 }
3770
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771 for (count=0; count<HZ*20; count++) {
3772 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303773 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3774 "downloadboot successful! (count=%d) IocState=%x\n",
3775 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003776 if (ioc->bus_type == SAS) {
3777 return 0;
3778 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303780 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3781 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 ioc->name));
3783 return -EFAULT;
3784 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303785 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3786 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 ioc->name));
3788 return 0;
3789 }
3790 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003791 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792 } else {
3793 mdelay (10);
3794 }
3795 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303796 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3797 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798 return -EFAULT;
3799}
3800
3801/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003802/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 * KickStart - Perform hard reset of MPT adapter.
3804 * @ioc: Pointer to MPT_ADAPTER structure
3805 * @force: Force hard reset
3806 * @sleepFlag: Specifies whether the process can sleep
3807 *
3808 * This routine places MPT adapter in diagnostic mode via the
3809 * WriteSequence register, and then performs a hard reset of adapter
3810 * via the Diagnostic register.
3811 *
3812 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3813 * or NO_SLEEP (interrupt thread, use mdelay)
3814 * force - 1 if doorbell active, board fault state
3815 * board operational, IOC_RECOVERY or
3816 * IOC_BRINGUP and there is an alt_ioc.
3817 * 0 else
3818 *
3819 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003820 * 1 - hard reset, READY
3821 * 0 - no reset due to History bit, READY
3822 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823 * OR reset but failed to come READY
3824 * -2 - no reset, could not enter DIAG mode
3825 * -3 - reset but bad FW bit
3826 */
3827static int
3828KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3829{
3830 int hard_reset_done = 0;
3831 u32 ioc_state=0;
3832 int cnt,cntdn;
3833
Eric Moore29dd3602007-09-14 18:46:51 -06003834 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003835 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 /* Always issue a Msg Unit Reset first. This will clear some
3837 * SCSI bus hang conditions.
3838 */
3839 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3840
3841 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003842 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843 } else {
3844 mdelay (1000);
3845 }
3846 }
3847
3848 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3849 if (hard_reset_done < 0)
3850 return hard_reset_done;
3851
Prakash, Sathya436ace72007-07-24 15:42:08 +05303852 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003853 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854
3855 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3856 for (cnt=0; cnt<cntdn; cnt++) {
3857 ioc_state = mpt_GetIocState(ioc, 1);
3858 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303859 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003860 ioc->name, cnt));
3861 return hard_reset_done;
3862 }
3863 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003864 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 } else {
3866 mdelay (10);
3867 }
3868 }
3869
Eric Moore29dd3602007-09-14 18:46:51 -06003870 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3871 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 return -1;
3873}
3874
3875/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003876/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 * mpt_diag_reset - Perform hard reset of the adapter.
3878 * @ioc: Pointer to MPT_ADAPTER structure
3879 * @ignore: Set if to honor and clear to ignore
3880 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003881 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882 * else set to NO_SLEEP (use mdelay instead)
3883 *
3884 * This routine places the adapter in diagnostic mode via the
3885 * WriteSequence register and then performs a hard reset of adapter
3886 * via the Diagnostic register. Adapter should be in ready state
3887 * upon successful completion.
3888 *
3889 * Returns: 1 hard reset successful
3890 * 0 no reset performed because reset history bit set
3891 * -2 enabling diagnostic mode failed
3892 * -3 diagnostic reset failed
3893 */
3894static int
3895mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3896{
3897 u32 diag0val;
3898 u32 doorbell;
3899 int hard_reset_done = 0;
3900 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303902 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Kashyap, Desaid1306912009-08-05 12:53:51 +05303903 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904
Eric Moorecd2c6192007-01-29 09:47:47 -07003905 /* Clear any existing interrupts */
3906 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3907
Eric Moore87cf8982006-06-27 16:09:26 -06003908 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303909
3910 if (!ignore)
3911 return 0;
3912
Prakash, Sathya436ace72007-07-24 15:42:08 +05303913 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003914 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003915 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3916 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3917 if (sleepFlag == CAN_SLEEP)
3918 msleep(1);
3919 else
3920 mdelay(1);
3921
Kashyap, Desaid1306912009-08-05 12:53:51 +05303922 /*
3923 * Call each currently registered protocol IOC reset handler
3924 * with pre-reset indication.
3925 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3926 * MptResetHandlers[] registered yet.
3927 */
3928 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3929 if (MptResetHandlers[cb_idx])
3930 (*(MptResetHandlers[cb_idx]))(ioc,
3931 MPT_IOC_PRE_RESET);
3932 }
3933
Eric Moore87cf8982006-06-27 16:09:26 -06003934 for (count = 0; count < 60; count ++) {
3935 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3936 doorbell &= MPI_IOC_STATE_MASK;
3937
Prakash, Sathya436ace72007-07-24 15:42:08 +05303938 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003939 "looking for READY STATE: doorbell=%x"
3940 " count=%d\n",
3941 ioc->name, doorbell, count));
Kashyap, Desai2f187862009-05-29 16:52:37 +05303942
Eric Moore87cf8982006-06-27 16:09:26 -06003943 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003944 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003945 }
3946
3947 /* wait 1 sec */
3948 if (sleepFlag == CAN_SLEEP)
3949 msleep(1000);
3950 else
3951 mdelay(1000);
3952 }
3953 return -1;
3954 }
3955
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 /* Use "Diagnostic reset" method! (only thing available!) */
3957 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3958
Prakash, Sathya436ace72007-07-24 15:42:08 +05303959 if (ioc->debug_level & MPT_DEBUG) {
3960 if (ioc->alt_ioc)
3961 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3962 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303964 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965
3966 /* Do the reset if we are told to ignore the reset history
3967 * or if the reset history is 0
3968 */
3969 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3970 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3971 /* Write magic sequence to WriteSequence register
3972 * Loop until in diagnostic mode
3973 */
3974 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3975 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3976 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3977 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3978 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3979 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3980
3981 /* wait 100 msec */
3982 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003983 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 } else {
3985 mdelay (100);
3986 }
3987
3988 count++;
3989 if (count > 20) {
3990 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3991 ioc->name, diag0val);
3992 return -2;
3993
3994 }
3995
3996 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3997
Prakash, Sathya436ace72007-07-24 15:42:08 +05303998 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 ioc->name, diag0val));
4000 }
4001
Prakash, Sathya436ace72007-07-24 15:42:08 +05304002 if (ioc->debug_level & MPT_DEBUG) {
4003 if (ioc->alt_ioc)
4004 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4005 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304007 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 /*
4009 * Disable the ARM (Bug fix)
4010 *
4011 */
4012 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004013 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014
4015 /*
4016 * Now hit the reset bit in the Diagnostic register
4017 * (THE BIG HAMMER!) (Clears DRWE bit).
4018 */
4019 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
4020 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304021 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 ioc->name));
4023
4024 /*
4025 * Call each currently registered protocol IOC reset handler
4026 * with pre-reset indication.
4027 * NOTE: If we're doing _IOC_BRINGUP, there can be no
4028 * MptResetHandlers[] registered yet.
4029 */
Kashyap, Desaid1306912009-08-05 12:53:51 +05304030 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
4031 if (MptResetHandlers[cb_idx]) {
4032 mpt_signal_reset(cb_idx,
4033 ioc, MPT_IOC_PRE_RESET);
4034 if (ioc->alt_ioc) {
4035 mpt_signal_reset(cb_idx,
4036 ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 }
4038 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 }
4040
Eric Moore0ccdb002006-07-11 17:33:13 -06004041 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304042 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06004043 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304044 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4045 else
4046 cached_fw = NULL;
4047 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 /* If the DownloadBoot operation fails, the
4049 * IOC will be left unusable. This is a fatal error
4050 * case. _diag_reset will return < 0
4051 */
4052 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304053 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4055 break;
4056 }
4057
Prakash, Sathya436ace72007-07-24 15:42:08 +05304058 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304059 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 /* wait 1 sec */
4061 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004062 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 } else {
4064 mdelay (1000);
4065 }
4066 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304067 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004068 printk(MYIOC_s_WARN_FMT
4069 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070 }
4071
4072 } else {
4073 /* Wait for FW to reload and for board
4074 * to go to the READY state.
4075 * Maximum wait is 60 seconds.
4076 * If fail, no error will check again
4077 * with calling program.
4078 */
4079 for (count = 0; count < 60; count ++) {
4080 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4081 doorbell &= MPI_IOC_STATE_MASK;
4082
Kashyap, Desai2f187862009-05-29 16:52:37 +05304083 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4084 "looking for READY STATE: doorbell=%x"
4085 " count=%d\n", ioc->name, doorbell, count));
4086
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087 if (doorbell == MPI_IOC_STATE_READY) {
4088 break;
4089 }
4090
4091 /* wait 1 sec */
4092 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004093 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094 } else {
4095 mdelay (1000);
4096 }
4097 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05304098
4099 if (doorbell != MPI_IOC_STATE_READY)
4100 printk(MYIOC_s_ERR_FMT "Failed to come READY "
4101 "after reset! IocState=%x", ioc->name,
4102 doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103 }
4104 }
4105
4106 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304107 if (ioc->debug_level & MPT_DEBUG) {
4108 if (ioc->alt_ioc)
4109 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4110 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4111 ioc->name, diag0val, diag1val));
4112 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113
4114 /* Clear RESET_HISTORY bit! Place board in the
4115 * diagnostic mode to update the diag register.
4116 */
4117 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4118 count = 0;
4119 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4120 /* Write magic sequence to WriteSequence register
4121 * Loop until in diagnostic mode
4122 */
4123 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4124 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4125 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4126 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4127 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4128 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4129
4130 /* wait 100 msec */
4131 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004132 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133 } else {
4134 mdelay (100);
4135 }
4136
4137 count++;
4138 if (count > 20) {
4139 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4140 ioc->name, diag0val);
4141 break;
4142 }
4143 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4144 }
4145 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4146 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4147 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4148 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4149 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4150 ioc->name);
4151 }
4152
4153 /* Disable Diagnostic Mode
4154 */
4155 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4156
4157 /* Check FW reload status flags.
4158 */
4159 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4160 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4161 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4162 ioc->name, diag0val);
4163 return -3;
4164 }
4165
Prakash, Sathya436ace72007-07-24 15:42:08 +05304166 if (ioc->debug_level & MPT_DEBUG) {
4167 if (ioc->alt_ioc)
4168 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4169 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172
4173 /*
4174 * Reset flag that says we've enabled event notification
4175 */
4176 ioc->facts.EventState = 0;
4177
4178 if (ioc->alt_ioc)
4179 ioc->alt_ioc->facts.EventState = 0;
4180
4181 return hard_reset_done;
4182}
4183
4184/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004185/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 * SendIocReset - Send IOCReset request to MPT adapter.
4187 * @ioc: Pointer to MPT_ADAPTER structure
4188 * @reset_type: reset type, expected values are
4189 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004190 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 *
4192 * Send IOCReset request to the MPT adapter.
4193 *
4194 * Returns 0 for success, non-zero for failure.
4195 */
4196static int
4197SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4198{
4199 int r;
4200 u32 state;
4201 int cntdn, count;
4202
Prakash, Sathya436ace72007-07-24 15:42:08 +05304203 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204 ioc->name, reset_type));
4205 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4206 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4207 return r;
4208
4209 /* FW ACK'd request, wait for READY state
4210 */
4211 count = 0;
4212 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4213
4214 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4215 cntdn--;
4216 count++;
4217 if (!cntdn) {
4218 if (sleepFlag != CAN_SLEEP)
4219 count *= 10;
4220
Kashyap, Desai2f187862009-05-29 16:52:37 +05304221 printk(MYIOC_s_ERR_FMT
4222 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
4223 ioc->name, state, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224 return -ETIME;
4225 }
4226
4227 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004228 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229 } else {
4230 mdelay (1); /* 1 msec delay */
4231 }
4232 }
4233
4234 /* TODO!
4235 * Cleanup all event stuff for this IOC; re-issue EventNotification
4236 * request if needed.
4237 */
4238 if (ioc->facts.Function)
4239 ioc->facts.EventState = 0;
4240
4241 return 0;
4242}
4243
4244/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004245/**
4246 * initChainBuffers - Allocate memory for and initialize chain buffers
4247 * @ioc: Pointer to MPT_ADAPTER structure
4248 *
4249 * Allocates memory for and initializes chain buffers,
4250 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 */
4252static int
4253initChainBuffers(MPT_ADAPTER *ioc)
4254{
4255 u8 *mem;
4256 int sz, ii, num_chain;
4257 int scale, num_sge, numSGE;
4258
4259 /* ReqToChain size must equal the req_depth
4260 * index = req_idx
4261 */
4262 if (ioc->ReqToChain == NULL) {
4263 sz = ioc->req_depth * sizeof(int);
4264 mem = kmalloc(sz, GFP_ATOMIC);
4265 if (mem == NULL)
4266 return -1;
4267
4268 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304269 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 ioc->name, mem, sz));
4271 mem = kmalloc(sz, GFP_ATOMIC);
4272 if (mem == NULL)
4273 return -1;
4274
4275 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304276 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277 ioc->name, mem, sz));
4278 }
4279 for (ii = 0; ii < ioc->req_depth; ii++) {
4280 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4281 }
4282
4283 /* ChainToChain size must equal the total number
4284 * of chain buffers to be allocated.
4285 * index = chain_idx
4286 *
4287 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004288 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 *
4290 * num_sge = num sge in request frame + last chain buffer
4291 * scale = num sge per chain buffer if no chain element
4292 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304293 scale = ioc->req_sz / ioc->SGE_size;
4294 if (ioc->sg_addr_size == sizeof(u64))
4295 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304297 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304299 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304301 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304303 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4304 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304306 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 ioc->name, num_sge, numSGE));
4308
Kashyap, Desai2f187862009-05-29 16:52:37 +05304309 if (ioc->bus_type == FC) {
4310 if (numSGE > MPT_SCSI_FC_SG_DEPTH)
4311 numSGE = MPT_SCSI_FC_SG_DEPTH;
4312 } else {
4313 if (numSGE > MPT_SCSI_SG_DEPTH)
4314 numSGE = MPT_SCSI_SG_DEPTH;
4315 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316
4317 num_chain = 1;
4318 while (numSGE - num_sge > 0) {
4319 num_chain++;
4320 num_sge += (scale - 1);
4321 }
4322 num_chain++;
4323
Prakash, Sathya436ace72007-07-24 15:42:08 +05304324 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325 ioc->name, numSGE, num_sge, num_chain));
4326
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004327 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 num_chain *= MPT_SCSI_CAN_QUEUE;
Anatolij Gustschinf1053a72009-12-12 14:52:21 +01004329 else if (ioc->bus_type == SAS)
4330 num_chain *= MPT_SAS_CAN_QUEUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331 else
4332 num_chain *= MPT_FC_CAN_QUEUE;
4333
4334 ioc->num_chain = num_chain;
4335
4336 sz = num_chain * sizeof(int);
4337 if (ioc->ChainToChain == NULL) {
4338 mem = kmalloc(sz, GFP_ATOMIC);
4339 if (mem == NULL)
4340 return -1;
4341
4342 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304343 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 ioc->name, mem, sz));
4345 } else {
4346 mem = (u8 *) ioc->ChainToChain;
4347 }
4348 memset(mem, 0xFF, sz);
4349 return num_chain;
4350}
4351
4352/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004353/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4355 * @ioc: Pointer to MPT_ADAPTER structure
4356 *
4357 * This routine allocates memory for the MPT reply and request frame
4358 * pools (if necessary), and primes the IOC reply FIFO with
4359 * reply frames.
4360 *
4361 * Returns 0 for success, non-zero for failure.
4362 */
4363static int
4364PrimeIocFifos(MPT_ADAPTER *ioc)
4365{
4366 MPT_FRAME_HDR *mf;
4367 unsigned long flags;
4368 dma_addr_t alloc_dma;
4369 u8 *mem;
4370 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304371 u64 dma_mask;
4372
4373 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374
4375 /* Prime reply FIFO... */
4376
4377 if (ioc->reply_frames == NULL) {
4378 if ( (num_chain = initChainBuffers(ioc)) < 0)
4379 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304380 /*
4381 * 1078 errata workaround for the 36GB limitation
4382 */
4383 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
Andrew Morton8e20ce92009-06-18 16:49:17 -07004384 ioc->dma_mask > DMA_BIT_MASK(35)) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304385 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4386 && !pci_set_consistent_dma_mask(ioc->pcidev,
4387 DMA_BIT_MASK(32))) {
Andrew Morton8e20ce92009-06-18 16:49:17 -07004388 dma_mask = DMA_BIT_MASK(35);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304389 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4390 "setting 35 bit addressing for "
4391 "Request/Reply/Chain and Sense Buffers\n",
4392 ioc->name));
4393 } else {
4394 /*Reseting DMA mask to 64 bit*/
4395 pci_set_dma_mask(ioc->pcidev,
4396 DMA_BIT_MASK(64));
4397 pci_set_consistent_dma_mask(ioc->pcidev,
4398 DMA_BIT_MASK(64));
4399
4400 printk(MYIOC_s_ERR_FMT
4401 "failed setting 35 bit addressing for "
4402 "Request/Reply/Chain and Sense Buffers\n",
4403 ioc->name);
4404 return -1;
4405 }
4406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407
4408 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304409 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304411 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 ioc->name, reply_sz, reply_sz));
4413
4414 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304415 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304417 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 ioc->name, sz, sz));
4419 total_size += sz;
4420
4421 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304422 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304424 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425 ioc->name, sz, sz, num_chain));
4426
4427 total_size += sz;
4428 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4429 if (mem == NULL) {
4430 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4431 ioc->name);
4432 goto out_fail;
4433 }
4434
Prakash, Sathya436ace72007-07-24 15:42:08 +05304435 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4437
4438 memset(mem, 0, total_size);
4439 ioc->alloc_total += total_size;
4440 ioc->alloc = mem;
4441 ioc->alloc_dma = alloc_dma;
4442 ioc->alloc_sz = total_size;
4443 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4444 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4445
Prakash, Sathya436ace72007-07-24 15:42:08 +05304446 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004447 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4448
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 alloc_dma += reply_sz;
4450 mem += reply_sz;
4451
4452 /* Request FIFO - WE manage this! */
4453
4454 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4455 ioc->req_frames_dma = alloc_dma;
4456
Prakash, Sathya436ace72007-07-24 15:42:08 +05304457 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 ioc->name, mem, (void *)(ulong)alloc_dma));
4459
4460 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4461
4462#if defined(CONFIG_MTRR) && 0
4463 /*
4464 * Enable Write Combining MTRR for IOC's memory region.
4465 * (at least as much as we can; "size and base must be
4466 * multiples of 4 kiB"
4467 */
4468 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4469 sz,
4470 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304471 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472 ioc->name, ioc->req_frames_dma, sz));
4473#endif
4474
4475 for (i = 0; i < ioc->req_depth; i++) {
4476 alloc_dma += ioc->req_sz;
4477 mem += ioc->req_sz;
4478 }
4479
4480 ioc->ChainBuffer = mem;
4481 ioc->ChainBufferDMA = alloc_dma;
4482
Prakash, Sathya436ace72007-07-24 15:42:08 +05304483 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4485
4486 /* Initialize the free chain Q.
4487 */
4488
4489 INIT_LIST_HEAD(&ioc->FreeChainQ);
4490
4491 /* Post the chain buffers to the FreeChainQ.
4492 */
4493 mem = (u8 *)ioc->ChainBuffer;
4494 for (i=0; i < num_chain; i++) {
4495 mf = (MPT_FRAME_HDR *) mem;
4496 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4497 mem += ioc->req_sz;
4498 }
4499
4500 /* Initialize Request frames linked list
4501 */
4502 alloc_dma = ioc->req_frames_dma;
4503 mem = (u8 *) ioc->req_frames;
4504
4505 spin_lock_irqsave(&ioc->FreeQlock, flags);
4506 INIT_LIST_HEAD(&ioc->FreeQ);
4507 for (i = 0; i < ioc->req_depth; i++) {
4508 mf = (MPT_FRAME_HDR *) mem;
4509
4510 /* Queue REQUESTs *internally*! */
4511 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4512
4513 mem += ioc->req_sz;
4514 }
4515 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4516
4517 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4518 ioc->sense_buf_pool =
4519 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4520 if (ioc->sense_buf_pool == NULL) {
4521 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4522 ioc->name);
4523 goto out_fail;
4524 }
4525
4526 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4527 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304528 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4530
4531 }
4532
4533 /* Post Reply frames to FIFO
4534 */
4535 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304536 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4538
4539 for (i = 0; i < ioc->reply_depth; i++) {
4540 /* Write each address to the IOC! */
4541 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4542 alloc_dma += ioc->reply_sz;
4543 }
4544
Andrew Morton8e20ce92009-06-18 16:49:17 -07004545 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304546 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4547 ioc->dma_mask))
4548 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4549 "restoring 64 bit addressing\n", ioc->name));
4550
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551 return 0;
4552
4553out_fail:
Kashyap, Desai2f187862009-05-29 16:52:37 +05304554
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555 if (ioc->alloc != NULL) {
4556 sz = ioc->alloc_sz;
4557 pci_free_consistent(ioc->pcidev,
4558 sz,
4559 ioc->alloc, ioc->alloc_dma);
4560 ioc->reply_frames = NULL;
4561 ioc->req_frames = NULL;
4562 ioc->alloc_total -= sz;
4563 }
4564 if (ioc->sense_buf_pool != NULL) {
4565 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4566 pci_free_consistent(ioc->pcidev,
4567 sz,
4568 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4569 ioc->sense_buf_pool = NULL;
4570 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304571
Andrew Morton8e20ce92009-06-18 16:49:17 -07004572 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304573 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4574 DMA_BIT_MASK(64)))
4575 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4576 "restoring 64 bit addressing\n", ioc->name));
4577
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 return -1;
4579}
4580
4581/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4582/**
4583 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4584 * from IOC via doorbell handshake method.
4585 * @ioc: Pointer to MPT_ADAPTER structure
4586 * @reqBytes: Size of the request in bytes
4587 * @req: Pointer to MPT request frame
4588 * @replyBytes: Expected size of the reply in bytes
4589 * @u16reply: Pointer to area where reply should be written
4590 * @maxwait: Max wait time for a reply (in seconds)
4591 * @sleepFlag: Specifies whether the process can sleep
4592 *
4593 * NOTES: It is the callers responsibility to byte-swap fields in the
4594 * request which are greater than 1 byte in size. It is also the
4595 * callers responsibility to byte-swap response fields which are
4596 * greater than 1 byte in size.
4597 *
4598 * Returns 0 for success, non-zero for failure.
4599 */
4600static int
4601mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004602 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603{
4604 MPIDefaultReply_t *mptReply;
4605 int failcnt = 0;
4606 int t;
4607
4608 /*
4609 * Get ready to cache a handshake reply
4610 */
4611 ioc->hs_reply_idx = 0;
4612 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4613 mptReply->MsgLength = 0;
4614
4615 /*
4616 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4617 * then tell IOC that we want to handshake a request of N words.
4618 * (WRITE u32val to Doorbell reg).
4619 */
4620 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4621 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4622 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4623 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4624
4625 /*
4626 * Wait for IOC's doorbell handshake int
4627 */
4628 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4629 failcnt++;
4630
Prakash, Sathya436ace72007-07-24 15:42:08 +05304631 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4633
4634 /* Read doorbell and check for active bit */
4635 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4636 return -1;
4637
4638 /*
4639 * Clear doorbell int (WRITE 0 to IntStatus reg),
4640 * then wait for IOC to ACKnowledge that it's ready for
4641 * our handshake request.
4642 */
4643 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4644 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4645 failcnt++;
4646
4647 if (!failcnt) {
4648 int ii;
4649 u8 *req_as_bytes = (u8 *) req;
4650
4651 /*
4652 * Stuff request words via doorbell handshake,
4653 * with ACK from IOC for each.
4654 */
4655 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4656 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4657 (req_as_bytes[(ii*4) + 1] << 8) |
4658 (req_as_bytes[(ii*4) + 2] << 16) |
4659 (req_as_bytes[(ii*4) + 3] << 24));
4660
4661 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4662 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4663 failcnt++;
4664 }
4665
Prakash, Sathya436ace72007-07-24 15:42:08 +05304666 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004667 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668
Prakash, Sathya436ace72007-07-24 15:42:08 +05304669 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4671
4672 /*
4673 * Wait for completion of doorbell handshake reply from the IOC
4674 */
4675 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4676 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004677
Prakash, Sathya436ace72007-07-24 15:42:08 +05304678 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4680
4681 /*
4682 * Copy out the cached reply...
4683 */
4684 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4685 u16reply[ii] = ioc->hs_reply[ii];
4686 } else {
4687 return -99;
4688 }
4689
4690 return -failcnt;
4691}
4692
4693/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004694/**
4695 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004696 * @ioc: Pointer to MPT_ADAPTER structure
4697 * @howlong: How long to wait (in seconds)
4698 * @sleepFlag: Specifies whether the process can sleep
4699 *
4700 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004701 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4702 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703 *
4704 * Returns a negative value on failure, else wait loop count.
4705 */
4706static int
4707WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4708{
4709 int cntdn;
4710 int count = 0;
4711 u32 intstat=0;
4712
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004713 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714
4715 if (sleepFlag == CAN_SLEEP) {
4716 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004717 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004718 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4719 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4720 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 count++;
4722 }
4723 } else {
4724 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004725 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4727 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4728 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729 count++;
4730 }
4731 }
4732
4733 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304734 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735 ioc->name, count));
4736 return count;
4737 }
4738
4739 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4740 ioc->name, count, intstat);
4741 return -1;
4742}
4743
4744/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004745/**
4746 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 * @ioc: Pointer to MPT_ADAPTER structure
4748 * @howlong: How long to wait (in seconds)
4749 * @sleepFlag: Specifies whether the process can sleep
4750 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004751 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4752 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753 *
4754 * Returns a negative value on failure, else wait loop count.
4755 */
4756static int
4757WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4758{
4759 int cntdn;
4760 int count = 0;
4761 u32 intstat=0;
4762
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004763 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764 if (sleepFlag == CAN_SLEEP) {
4765 while (--cntdn) {
4766 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4767 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4768 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004769 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770 count++;
4771 }
4772 } else {
4773 while (--cntdn) {
4774 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4775 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4776 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004777 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778 count++;
4779 }
4780 }
4781
4782 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304783 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784 ioc->name, count, howlong));
4785 return count;
4786 }
4787
4788 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4789 ioc->name, count, intstat);
4790 return -1;
4791}
4792
4793/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004794/**
4795 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796 * @ioc: Pointer to MPT_ADAPTER structure
4797 * @howlong: How long to wait (in seconds)
4798 * @sleepFlag: Specifies whether the process can sleep
4799 *
4800 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4801 * Reply is cached to IOC private area large enough to hold a maximum
4802 * of 128 bytes of reply data.
4803 *
4804 * Returns a negative value on failure, else size of reply in WORDS.
4805 */
4806static int
4807WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4808{
4809 int u16cnt = 0;
4810 int failcnt = 0;
4811 int t;
4812 u16 *hs_reply = ioc->hs_reply;
4813 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4814 u16 hword;
4815
4816 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4817
4818 /*
4819 * Get first two u16's so we can look at IOC's intended reply MsgLength
4820 */
4821 u16cnt=0;
4822 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4823 failcnt++;
4824 } else {
4825 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4826 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4827 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4828 failcnt++;
4829 else {
4830 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4831 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4832 }
4833 }
4834
Prakash, Sathya436ace72007-07-24 15:42:08 +05304835 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004836 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4838
4839 /*
4840 * If no error (and IOC said MsgLength is > 0), piece together
4841 * reply 16 bits at a time.
4842 */
4843 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4844 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4845 failcnt++;
4846 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4847 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004848 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849 hs_reply[u16cnt] = hword;
4850 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4851 }
4852
4853 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4854 failcnt++;
4855 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4856
4857 if (failcnt) {
4858 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4859 ioc->name);
4860 return -failcnt;
4861 }
4862#if 0
4863 else if (u16cnt != (2 * mptReply->MsgLength)) {
4864 return -101;
4865 }
4866 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4867 return -102;
4868 }
4869#endif
4870
Prakash, Sathya436ace72007-07-24 15:42:08 +05304871 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004872 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873
Prakash, Sathya436ace72007-07-24 15:42:08 +05304874 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 ioc->name, t, u16cnt/2));
4876 return u16cnt/2;
4877}
4878
4879/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004880/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 * GetLanConfigPages - Fetch LANConfig pages.
4882 * @ioc: Pointer to MPT_ADAPTER structure
4883 *
4884 * Return: 0 for success
4885 * -ENOMEM if no memory available
4886 * -EPERM if not allowed due to ISR context
4887 * -EAGAIN if no msg frames currently available
4888 * -EFAULT for non-successful reply or no reply (timeout)
4889 */
4890static int
4891GetLanConfigPages(MPT_ADAPTER *ioc)
4892{
4893 ConfigPageHeader_t hdr;
4894 CONFIGPARMS cfg;
4895 LANPage0_t *ppage0_alloc;
4896 dma_addr_t page0_dma;
4897 LANPage1_t *ppage1_alloc;
4898 dma_addr_t page1_dma;
4899 int rc = 0;
4900 int data_sz;
4901 int copy_sz;
4902
4903 /* Get LAN Page 0 header */
4904 hdr.PageVersion = 0;
4905 hdr.PageLength = 0;
4906 hdr.PageNumber = 0;
4907 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004908 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909 cfg.physAddr = -1;
4910 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4911 cfg.dir = 0;
4912 cfg.pageAddr = 0;
4913 cfg.timeout = 0;
4914
4915 if ((rc = mpt_config(ioc, &cfg)) != 0)
4916 return rc;
4917
4918 if (hdr.PageLength > 0) {
4919 data_sz = hdr.PageLength * 4;
4920 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4921 rc = -ENOMEM;
4922 if (ppage0_alloc) {
4923 memset((u8 *)ppage0_alloc, 0, data_sz);
4924 cfg.physAddr = page0_dma;
4925 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4926
4927 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4928 /* save the data */
4929 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4930 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4931
4932 }
4933
4934 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4935
4936 /* FIXME!
4937 * Normalize endianness of structure data,
4938 * by byte-swapping all > 1 byte fields!
4939 */
4940
4941 }
4942
4943 if (rc)
4944 return rc;
4945 }
4946
4947 /* Get LAN Page 1 header */
4948 hdr.PageVersion = 0;
4949 hdr.PageLength = 0;
4950 hdr.PageNumber = 1;
4951 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004952 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953 cfg.physAddr = -1;
4954 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4955 cfg.dir = 0;
4956 cfg.pageAddr = 0;
4957
4958 if ((rc = mpt_config(ioc, &cfg)) != 0)
4959 return rc;
4960
4961 if (hdr.PageLength == 0)
4962 return 0;
4963
4964 data_sz = hdr.PageLength * 4;
4965 rc = -ENOMEM;
4966 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4967 if (ppage1_alloc) {
4968 memset((u8 *)ppage1_alloc, 0, data_sz);
4969 cfg.physAddr = page1_dma;
4970 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4971
4972 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4973 /* save the data */
4974 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4975 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4976 }
4977
4978 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4979
4980 /* FIXME!
4981 * Normalize endianness of structure data,
4982 * by byte-swapping all > 1 byte fields!
4983 */
4984
4985 }
4986
4987 return rc;
4988}
4989
4990/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004991/**
4992 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004993 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004994 * @persist_opcode: see below
4995 *
4996 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4997 * devices not currently present.
4998 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4999 *
5000 * NOTE: Don't use not this function during interrupt time.
5001 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005002 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005003 */
5004
5005/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5006int
5007mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
5008{
5009 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
5010 SasIoUnitControlReply_t *sasIoUnitCntrReply;
5011 MPT_FRAME_HDR *mf = NULL;
5012 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305013 int ret = 0;
5014 unsigned long timeleft;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005015
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305016 mutex_lock(&ioc->mptbase_cmds.mutex);
5017
5018 /* init the internal cmd struct */
5019 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
5020 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005021
5022 /* insure garbage is not sent to fw */
5023 switch(persist_opcode) {
5024
5025 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
5026 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
5027 break;
5028
5029 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305030 ret = -1;
5031 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005032 }
5033
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305034 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
5035 __func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005036
5037 /* Get a MF for this command.
5038 */
5039 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305040 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
5041 ret = -1;
5042 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005043 }
5044
5045 mpi_hdr = (MPIHeader_t *) mf;
5046 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
5047 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
5048 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
5049 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
5050 sasIoUnitCntrReq->Operation = persist_opcode;
5051
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005052 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305053 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
5054 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
5055 ret = -ETIME;
5056 printk(KERN_DEBUG "%s: failed\n", __func__);
5057 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
5058 goto out;
5059 if (!timeleft) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09005060 printk(MYIOC_s_WARN_FMT
5061 "Issuing Reset from %s!!, doorbell=0x%08x\n",
5062 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05305063 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305064 mpt_free_msg_frame(ioc, mf);
5065 }
5066 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005067 }
5068
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305069 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
5070 ret = -1;
5071 goto out;
5072 }
5073
5074 sasIoUnitCntrReply =
5075 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5076 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5077 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5078 __func__, sasIoUnitCntrReply->IOCStatus,
5079 sasIoUnitCntrReply->IOCLogInfo);
5080 printk(KERN_DEBUG "%s: failed\n", __func__);
5081 ret = -1;
5082 } else
5083 printk(KERN_DEBUG "%s: success\n", __func__);
5084 out:
5085
5086 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5087 mutex_unlock(&ioc->mptbase_cmds.mutex);
5088 return ret;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005089}
5090
5091/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005092
5093static void
5094mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5095 MpiEventDataRaid_t * pRaidEventData)
5096{
5097 int volume;
5098 int reason;
5099 int disk;
5100 int status;
5101 int flags;
5102 int state;
5103
5104 volume = pRaidEventData->VolumeID;
5105 reason = pRaidEventData->ReasonCode;
5106 disk = pRaidEventData->PhysDiskNum;
5107 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5108 flags = (status >> 0) & 0xff;
5109 state = (status >> 8) & 0xff;
5110
5111 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5112 return;
5113 }
5114
5115 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5116 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5117 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005118 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5119 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005120 } else {
5121 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5122 ioc->name, volume);
5123 }
5124
5125 switch(reason) {
5126 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5127 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5128 ioc->name);
5129 break;
5130
5131 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5132
5133 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5134 ioc->name);
5135 break;
5136
5137 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5138 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5139 ioc->name);
5140 break;
5141
5142 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5143 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5144 ioc->name,
5145 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5146 ? "optimal"
5147 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5148 ? "degraded"
5149 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5150 ? "failed"
5151 : "state unknown",
5152 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5153 ? ", enabled" : "",
5154 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5155 ? ", quiesced" : "",
5156 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5157 ? ", resync in progress" : "" );
5158 break;
5159
5160 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5161 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5162 ioc->name, disk);
5163 break;
5164
5165 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5166 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5167 ioc->name);
5168 break;
5169
5170 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5171 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5172 ioc->name);
5173 break;
5174
5175 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5176 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5177 ioc->name);
5178 break;
5179
5180 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5181 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5182 ioc->name,
5183 state == MPI_PHYSDISK0_STATUS_ONLINE
5184 ? "online"
5185 : state == MPI_PHYSDISK0_STATUS_MISSING
5186 ? "missing"
5187 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5188 ? "not compatible"
5189 : state == MPI_PHYSDISK0_STATUS_FAILED
5190 ? "failed"
5191 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5192 ? "initializing"
5193 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5194 ? "offline requested"
5195 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5196 ? "failed requested"
5197 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5198 ? "offline"
5199 : "state unknown",
5200 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5201 ? ", out of sync" : "",
5202 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5203 ? ", quiesced" : "" );
5204 break;
5205
5206 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5207 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5208 ioc->name, disk);
5209 break;
5210
5211 case MPI_EVENT_RAID_RC_SMART_DATA:
5212 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5213 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5214 break;
5215
5216 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5217 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5218 ioc->name, disk);
5219 break;
5220 }
5221}
5222
5223/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005224/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5226 * @ioc: Pointer to MPT_ADAPTER structure
5227 *
5228 * Returns: 0 for success
5229 * -ENOMEM if no memory available
5230 * -EPERM if not allowed due to ISR context
5231 * -EAGAIN if no msg frames currently available
5232 * -EFAULT for non-successful reply or no reply (timeout)
5233 */
5234static int
5235GetIoUnitPage2(MPT_ADAPTER *ioc)
5236{
5237 ConfigPageHeader_t hdr;
5238 CONFIGPARMS cfg;
5239 IOUnitPage2_t *ppage_alloc;
5240 dma_addr_t page_dma;
5241 int data_sz;
5242 int rc;
5243
5244 /* Get the page header */
5245 hdr.PageVersion = 0;
5246 hdr.PageLength = 0;
5247 hdr.PageNumber = 2;
5248 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005249 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 cfg.physAddr = -1;
5251 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5252 cfg.dir = 0;
5253 cfg.pageAddr = 0;
5254 cfg.timeout = 0;
5255
5256 if ((rc = mpt_config(ioc, &cfg)) != 0)
5257 return rc;
5258
5259 if (hdr.PageLength == 0)
5260 return 0;
5261
5262 /* Read the config page */
5263 data_sz = hdr.PageLength * 4;
5264 rc = -ENOMEM;
5265 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5266 if (ppage_alloc) {
5267 memset((u8 *)ppage_alloc, 0, data_sz);
5268 cfg.physAddr = page_dma;
5269 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5270
5271 /* If Good, save data */
5272 if ((rc = mpt_config(ioc, &cfg)) == 0)
5273 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5274
5275 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5276 }
5277
5278 return rc;
5279}
5280
5281/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005282/**
5283 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005284 * @ioc: Pointer to a Adapter Strucutre
5285 * @portnum: IOC port number
5286 *
5287 * Return: -EFAULT if read of config page header fails
5288 * or if no nvram
5289 * If read of SCSI Port Page 0 fails,
5290 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5291 * Adapter settings: async, narrow
5292 * Return 1
5293 * If read of SCSI Port Page 2 fails,
5294 * Adapter settings valid
5295 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5296 * Return 1
5297 * Else
5298 * Both valid
5299 * Return 0
5300 * CHECK - what type of locking mechanisms should be used????
5301 */
5302static int
5303mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5304{
5305 u8 *pbuf;
5306 dma_addr_t buf_dma;
5307 CONFIGPARMS cfg;
5308 ConfigPageHeader_t header;
5309 int ii;
5310 int data, rc = 0;
5311
5312 /* Allocate memory
5313 */
5314 if (!ioc->spi_data.nvram) {
5315 int sz;
5316 u8 *mem;
5317 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5318 mem = kmalloc(sz, GFP_ATOMIC);
5319 if (mem == NULL)
5320 return -EFAULT;
5321
5322 ioc->spi_data.nvram = (int *) mem;
5323
Prakash, Sathya436ace72007-07-24 15:42:08 +05305324 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005325 ioc->name, ioc->spi_data.nvram, sz));
5326 }
5327
5328 /* Invalidate NVRAM information
5329 */
5330 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5331 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5332 }
5333
5334 /* Read SPP0 header, allocate memory, then read page.
5335 */
5336 header.PageVersion = 0;
5337 header.PageLength = 0;
5338 header.PageNumber = 0;
5339 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005340 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005341 cfg.physAddr = -1;
5342 cfg.pageAddr = portnum;
5343 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5344 cfg.dir = 0;
5345 cfg.timeout = 0; /* use default */
5346 if (mpt_config(ioc, &cfg) != 0)
5347 return -EFAULT;
5348
5349 if (header.PageLength > 0) {
5350 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5351 if (pbuf) {
5352 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5353 cfg.physAddr = buf_dma;
5354 if (mpt_config(ioc, &cfg) != 0) {
5355 ioc->spi_data.maxBusWidth = MPT_NARROW;
5356 ioc->spi_data.maxSyncOffset = 0;
5357 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5358 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5359 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305360 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5361 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005362 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363 } else {
5364 /* Save the Port Page 0 data
5365 */
5366 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5367 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5368 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5369
5370 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5371 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005372 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5373 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005374 ioc->name, pPP0->Capabilities));
5375 }
5376 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5377 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5378 if (data) {
5379 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5380 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5381 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305382 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5383 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005384 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385 } else {
5386 ioc->spi_data.maxSyncOffset = 0;
5387 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5388 }
5389
5390 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5391
5392 /* Update the minSyncFactor based on bus type.
5393 */
5394 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5395 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5396
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005397 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305399 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5400 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005401 ioc->name, ioc->spi_data.minSyncFactor));
5402 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403 }
5404 }
5405 if (pbuf) {
5406 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5407 }
5408 }
5409 }
5410
5411 /* SCSI Port Page 2 - Read the header then the page.
5412 */
5413 header.PageVersion = 0;
5414 header.PageLength = 0;
5415 header.PageNumber = 2;
5416 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005417 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418 cfg.physAddr = -1;
5419 cfg.pageAddr = portnum;
5420 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5421 cfg.dir = 0;
5422 if (mpt_config(ioc, &cfg) != 0)
5423 return -EFAULT;
5424
5425 if (header.PageLength > 0) {
5426 /* Allocate memory and read SCSI Port Page 2
5427 */
5428 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5429 if (pbuf) {
5430 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5431 cfg.physAddr = buf_dma;
5432 if (mpt_config(ioc, &cfg) != 0) {
5433 /* Nvram data is left with INVALID mark
5434 */
5435 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005436 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5437
5438 /* This is an ATTO adapter, read Page2 accordingly
5439 */
5440 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5441 ATTODeviceInfo_t *pdevice = NULL;
5442 u16 ATTOFlags;
5443
5444 /* Save the Port Page 2 data
5445 * (reformat into a 32bit quantity)
5446 */
5447 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5448 pdevice = &pPP2->DeviceSettings[ii];
5449 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5450 data = 0;
5451
5452 /* Translate ATTO device flags to LSI format
5453 */
5454 if (ATTOFlags & ATTOFLAG_DISC)
5455 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5456 if (ATTOFlags & ATTOFLAG_ID_ENB)
5457 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5458 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5459 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5460 if (ATTOFlags & ATTOFLAG_TAGGED)
5461 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5462 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5463 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5464
5465 data = (data << 16) | (pdevice->Period << 8) | 10;
5466 ioc->spi_data.nvram[ii] = data;
5467 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468 } else {
5469 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5470 MpiDeviceInfo_t *pdevice = NULL;
5471
Moore, Ericd8e925d2006-01-16 18:53:06 -07005472 /*
5473 * Save "Set to Avoid SCSI Bus Resets" flag
5474 */
5475 ioc->spi_data.bus_reset =
5476 (le32_to_cpu(pPP2->PortFlags) &
5477 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5478 0 : 1 ;
5479
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480 /* Save the Port Page 2 data
5481 * (reformat into a 32bit quantity)
5482 */
5483 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5484 ioc->spi_data.PortFlags = data;
5485 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5486 pdevice = &pPP2->DeviceSettings[ii];
5487 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5488 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5489 ioc->spi_data.nvram[ii] = data;
5490 }
5491 }
5492
5493 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5494 }
5495 }
5496
5497 /* Update Adapter limits with those from NVRAM
5498 * Comment: Don't need to do this. Target performance
5499 * parameters will never exceed the adapters limits.
5500 */
5501
5502 return rc;
5503}
5504
5505/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005506/**
5507 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508 * @ioc: Pointer to a Adapter Strucutre
5509 * @portnum: IOC port number
5510 *
5511 * Return: -EFAULT if read of config page header fails
5512 * or 0 if success.
5513 */
5514static int
5515mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5516{
5517 CONFIGPARMS cfg;
5518 ConfigPageHeader_t header;
5519
5520 /* Read the SCSI Device Page 1 header
5521 */
5522 header.PageVersion = 0;
5523 header.PageLength = 0;
5524 header.PageNumber = 1;
5525 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005526 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527 cfg.physAddr = -1;
5528 cfg.pageAddr = portnum;
5529 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5530 cfg.dir = 0;
5531 cfg.timeout = 0;
5532 if (mpt_config(ioc, &cfg) != 0)
5533 return -EFAULT;
5534
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005535 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5536 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537
5538 header.PageVersion = 0;
5539 header.PageLength = 0;
5540 header.PageNumber = 0;
5541 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5542 if (mpt_config(ioc, &cfg) != 0)
5543 return -EFAULT;
5544
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005545 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5546 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005547
Prakash, Sathya436ace72007-07-24 15:42:08 +05305548 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5550
Prakash, Sathya436ace72007-07-24 15:42:08 +05305551 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5553 return 0;
5554}
5555
Eric Mooreb506ade2007-01-29 09:45:37 -07005556/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005557 * mpt_inactive_raid_list_free - This clears this link list.
5558 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005559 **/
5560static void
5561mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5562{
5563 struct inactive_raid_component_info *component_info, *pNext;
5564
5565 if (list_empty(&ioc->raid_data.inactive_list))
5566 return;
5567
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005568 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005569 list_for_each_entry_safe(component_info, pNext,
5570 &ioc->raid_data.inactive_list, list) {
5571 list_del(&component_info->list);
5572 kfree(component_info);
5573 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005574 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005575}
5576
5577/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005578 * 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 -07005579 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005580 * @ioc : pointer to per adapter structure
5581 * @channel : volume channel
5582 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005583 **/
5584static void
5585mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5586{
5587 CONFIGPARMS cfg;
5588 ConfigPageHeader_t hdr;
5589 dma_addr_t dma_handle;
5590 pRaidVolumePage0_t buffer = NULL;
5591 int i;
5592 RaidPhysDiskPage0_t phys_disk;
5593 struct inactive_raid_component_info *component_info;
5594 int handle_inactive_volumes;
5595
5596 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5597 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5598 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5599 cfg.pageAddr = (channel << 8) + id;
5600 cfg.cfghdr.hdr = &hdr;
5601 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5602
5603 if (mpt_config(ioc, &cfg) != 0)
5604 goto out;
5605
5606 if (!hdr.PageLength)
5607 goto out;
5608
5609 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5610 &dma_handle);
5611
5612 if (!buffer)
5613 goto out;
5614
5615 cfg.physAddr = dma_handle;
5616 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5617
5618 if (mpt_config(ioc, &cfg) != 0)
5619 goto out;
5620
5621 if (!buffer->NumPhysDisks)
5622 goto out;
5623
5624 handle_inactive_volumes =
5625 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5626 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5627 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5628 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5629
5630 if (!handle_inactive_volumes)
5631 goto out;
5632
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005633 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005634 for (i = 0; i < buffer->NumPhysDisks; i++) {
5635 if(mpt_raid_phys_disk_pg0(ioc,
5636 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5637 continue;
5638
5639 if ((component_info = kmalloc(sizeof (*component_info),
5640 GFP_KERNEL)) == NULL)
5641 continue;
5642
5643 component_info->volumeID = id;
5644 component_info->volumeBus = channel;
5645 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5646 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5647 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5648 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5649
5650 list_add_tail(&component_info->list,
5651 &ioc->raid_data.inactive_list);
5652 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005653 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005654
5655 out:
5656 if (buffer)
5657 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5658 dma_handle);
5659}
5660
5661/**
5662 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5663 * @ioc: Pointer to a Adapter Structure
5664 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5665 * @phys_disk: requested payload data returned
5666 *
5667 * Return:
5668 * 0 on success
5669 * -EFAULT if read of config page header fails or data pointer not NULL
5670 * -ENOMEM if pci_alloc failed
5671 **/
5672int
Kashyap, Desai2f187862009-05-29 16:52:37 +05305673mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
5674 RaidPhysDiskPage0_t *phys_disk)
Eric Mooreb506ade2007-01-29 09:45:37 -07005675{
Kashyap, Desai2f187862009-05-29 16:52:37 +05305676 CONFIGPARMS cfg;
5677 ConfigPageHeader_t hdr;
Eric Mooreb506ade2007-01-29 09:45:37 -07005678 dma_addr_t dma_handle;
5679 pRaidPhysDiskPage0_t buffer = NULL;
5680 int rc;
5681
5682 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5683 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
Kashyap, Desai2f187862009-05-29 16:52:37 +05305684 memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
Eric Mooreb506ade2007-01-29 09:45:37 -07005685
Kashyap, Desai2f187862009-05-29 16:52:37 +05305686 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
Eric Mooreb506ade2007-01-29 09:45:37 -07005687 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5688 cfg.cfghdr.hdr = &hdr;
5689 cfg.physAddr = -1;
5690 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5691
5692 if (mpt_config(ioc, &cfg) != 0) {
5693 rc = -EFAULT;
5694 goto out;
5695 }
5696
5697 if (!hdr.PageLength) {
5698 rc = -EFAULT;
5699 goto out;
5700 }
5701
5702 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5703 &dma_handle);
5704
5705 if (!buffer) {
5706 rc = -ENOMEM;
5707 goto out;
5708 }
5709
5710 cfg.physAddr = dma_handle;
5711 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5712 cfg.pageAddr = phys_disk_num;
5713
5714 if (mpt_config(ioc, &cfg) != 0) {
5715 rc = -EFAULT;
5716 goto out;
5717 }
5718
5719 rc = 0;
5720 memcpy(phys_disk, buffer, sizeof(*buffer));
5721 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5722
5723 out:
5724
5725 if (buffer)
5726 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5727 dma_handle);
5728
5729 return rc;
5730}
5731
Linus Torvalds1da177e2005-04-16 15:20:36 -07005732/**
Kashyap, Desaia7938b02009-05-29 16:53:56 +05305733 * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
5734 * @ioc: Pointer to a Adapter Structure
5735 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5736 *
5737 * Return:
5738 * returns number paths
5739 **/
5740int
5741mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
5742{
5743 CONFIGPARMS cfg;
5744 ConfigPageHeader_t hdr;
5745 dma_addr_t dma_handle;
5746 pRaidPhysDiskPage1_t buffer = NULL;
5747 int rc;
5748
5749 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5750 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5751
5752 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5753 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5754 hdr.PageNumber = 1;
5755 cfg.cfghdr.hdr = &hdr;
5756 cfg.physAddr = -1;
5757 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5758
5759 if (mpt_config(ioc, &cfg) != 0) {
5760 rc = 0;
5761 goto out;
5762 }
5763
5764 if (!hdr.PageLength) {
5765 rc = 0;
5766 goto out;
5767 }
5768
5769 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5770 &dma_handle);
5771
5772 if (!buffer) {
5773 rc = 0;
5774 goto out;
5775 }
5776
5777 cfg.physAddr = dma_handle;
5778 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5779 cfg.pageAddr = phys_disk_num;
5780
5781 if (mpt_config(ioc, &cfg) != 0) {
5782 rc = 0;
5783 goto out;
5784 }
5785
5786 rc = buffer->NumPhysDiskPaths;
5787 out:
5788
5789 if (buffer)
5790 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5791 dma_handle);
5792
5793 return rc;
5794}
5795EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
5796
5797/**
5798 * mpt_raid_phys_disk_pg1 - returns phys disk page 1
5799 * @ioc: Pointer to a Adapter Structure
5800 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5801 * @phys_disk: requested payload data returned
5802 *
5803 * Return:
5804 * 0 on success
5805 * -EFAULT if read of config page header fails or data pointer not NULL
5806 * -ENOMEM if pci_alloc failed
5807 **/
5808int
5809mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
5810 RaidPhysDiskPage1_t *phys_disk)
5811{
5812 CONFIGPARMS cfg;
5813 ConfigPageHeader_t hdr;
5814 dma_addr_t dma_handle;
5815 pRaidPhysDiskPage1_t buffer = NULL;
5816 int rc;
5817 int i;
5818 __le64 sas_address;
5819
5820 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5821 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5822 rc = 0;
5823
5824 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5825 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5826 hdr.PageNumber = 1;
5827 cfg.cfghdr.hdr = &hdr;
5828 cfg.physAddr = -1;
5829 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5830
5831 if (mpt_config(ioc, &cfg) != 0) {
5832 rc = -EFAULT;
5833 goto out;
5834 }
5835
5836 if (!hdr.PageLength) {
5837 rc = -EFAULT;
5838 goto out;
5839 }
5840
5841 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5842 &dma_handle);
5843
5844 if (!buffer) {
5845 rc = -ENOMEM;
5846 goto out;
5847 }
5848
5849 cfg.physAddr = dma_handle;
5850 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5851 cfg.pageAddr = phys_disk_num;
5852
5853 if (mpt_config(ioc, &cfg) != 0) {
5854 rc = -EFAULT;
5855 goto out;
5856 }
5857
5858 phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
5859 phys_disk->PhysDiskNum = phys_disk_num;
5860 for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
5861 phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
5862 phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
5863 phys_disk->Path[i].OwnerIdentifier =
5864 buffer->Path[i].OwnerIdentifier;
5865 phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
5866 memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
5867 sas_address = le64_to_cpu(sas_address);
5868 memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
5869 memcpy(&sas_address,
5870 &buffer->Path[i].OwnerWWID, sizeof(__le64));
5871 sas_address = le64_to_cpu(sas_address);
5872 memcpy(&phys_disk->Path[i].OwnerWWID,
5873 &sas_address, sizeof(__le64));
5874 }
5875
5876 out:
5877
5878 if (buffer)
5879 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5880 dma_handle);
5881
5882 return rc;
5883}
5884EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
5885
5886
5887/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5889 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005890 *
5891 * Return:
5892 * 0 on success
5893 * -EFAULT if read of config page header fails or data pointer not NULL
5894 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005895 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005896int
5897mpt_findImVolumes(MPT_ADAPTER *ioc)
5898{
5899 IOCPage2_t *pIoc2;
5900 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005901 dma_addr_t ioc2_dma;
5902 CONFIGPARMS cfg;
5903 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005904 int rc = 0;
5905 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005906 int i;
5907
5908 if (!ioc->ir_firmware)
5909 return 0;
5910
5911 /* Free the old page
5912 */
5913 kfree(ioc->raid_data.pIocPg2);
5914 ioc->raid_data.pIocPg2 = NULL;
5915 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005916
5917 /* Read IOCP2 header then the page.
5918 */
5919 header.PageVersion = 0;
5920 header.PageLength = 0;
5921 header.PageNumber = 2;
5922 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005923 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005924 cfg.physAddr = -1;
5925 cfg.pageAddr = 0;
5926 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5927 cfg.dir = 0;
5928 cfg.timeout = 0;
5929 if (mpt_config(ioc, &cfg) != 0)
5930 return -EFAULT;
5931
5932 if (header.PageLength == 0)
5933 return -EFAULT;
5934
5935 iocpage2sz = header.PageLength * 4;
5936 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5937 if (!pIoc2)
5938 return -ENOMEM;
5939
5940 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5941 cfg.physAddr = ioc2_dma;
5942 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005943 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005944
Eric Mooreb506ade2007-01-29 09:45:37 -07005945 mem = kmalloc(iocpage2sz, GFP_KERNEL);
Julia Lawall1c1acab2010-08-11 12:11:24 +02005946 if (!mem) {
5947 rc = -ENOMEM;
Eric Mooreb506ade2007-01-29 09:45:37 -07005948 goto out;
Julia Lawall1c1acab2010-08-11 12:11:24 +02005949 }
Eric Mooreb506ade2007-01-29 09:45:37 -07005950
Linus Torvalds1da177e2005-04-16 15:20:36 -07005951 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005952 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953
Eric Mooreb506ade2007-01-29 09:45:37 -07005954 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955
Eric Mooreb506ade2007-01-29 09:45:37 -07005956 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5957 mpt_inactive_raid_volumes(ioc,
5958 pIoc2->RaidVolume[i].VolumeBus,
5959 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960
Eric Mooreb506ade2007-01-29 09:45:37 -07005961 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005962 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5963
5964 return rc;
5965}
5966
Moore, Ericc972c702006-03-14 09:14:06 -07005967static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005968mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5969{
5970 IOCPage3_t *pIoc3;
5971 u8 *mem;
5972 CONFIGPARMS cfg;
5973 ConfigPageHeader_t header;
5974 dma_addr_t ioc3_dma;
5975 int iocpage3sz = 0;
5976
5977 /* Free the old page
5978 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005979 kfree(ioc->raid_data.pIocPg3);
5980 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005981
5982 /* There is at least one physical disk.
5983 * Read and save IOC Page 3
5984 */
5985 header.PageVersion = 0;
5986 header.PageLength = 0;
5987 header.PageNumber = 3;
5988 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005989 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990 cfg.physAddr = -1;
5991 cfg.pageAddr = 0;
5992 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5993 cfg.dir = 0;
5994 cfg.timeout = 0;
5995 if (mpt_config(ioc, &cfg) != 0)
5996 return 0;
5997
5998 if (header.PageLength == 0)
5999 return 0;
6000
6001 /* Read Header good, alloc memory
6002 */
6003 iocpage3sz = header.PageLength * 4;
6004 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
6005 if (!pIoc3)
6006 return 0;
6007
6008 /* Read the Page and save the data
6009 * into malloc'd memory.
6010 */
6011 cfg.physAddr = ioc3_dma;
6012 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6013 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07006014 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006015 if (mem) {
6016 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006017 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006018 }
6019 }
6020
6021 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
6022
6023 return 0;
6024}
6025
6026static void
6027mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
6028{
6029 IOCPage4_t *pIoc4;
6030 CONFIGPARMS cfg;
6031 ConfigPageHeader_t header;
6032 dma_addr_t ioc4_dma;
6033 int iocpage4sz;
6034
6035 /* Read and save IOC Page 4
6036 */
6037 header.PageVersion = 0;
6038 header.PageLength = 0;
6039 header.PageNumber = 4;
6040 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006041 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006042 cfg.physAddr = -1;
6043 cfg.pageAddr = 0;
6044 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6045 cfg.dir = 0;
6046 cfg.timeout = 0;
6047 if (mpt_config(ioc, &cfg) != 0)
6048 return;
6049
6050 if (header.PageLength == 0)
6051 return;
6052
6053 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
6054 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
6055 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
6056 if (!pIoc4)
6057 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06006058 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059 } else {
6060 ioc4_dma = ioc->spi_data.IocPg4_dma;
6061 iocpage4sz = ioc->spi_data.IocPg4Sz;
6062 }
6063
6064 /* Read the Page into dma memory.
6065 */
6066 cfg.physAddr = ioc4_dma;
6067 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6068 if (mpt_config(ioc, &cfg) == 0) {
6069 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
6070 ioc->spi_data.IocPg4_dma = ioc4_dma;
6071 ioc->spi_data.IocPg4Sz = iocpage4sz;
6072 } else {
6073 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
6074 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06006075 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006076 }
6077}
6078
6079static void
6080mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
6081{
6082 IOCPage1_t *pIoc1;
6083 CONFIGPARMS cfg;
6084 ConfigPageHeader_t header;
6085 dma_addr_t ioc1_dma;
6086 int iocpage1sz = 0;
6087 u32 tmp;
6088
6089 /* Check the Coalescing Timeout in IOC Page 1
6090 */
6091 header.PageVersion = 0;
6092 header.PageLength = 0;
6093 header.PageNumber = 1;
6094 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006095 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006096 cfg.physAddr = -1;
6097 cfg.pageAddr = 0;
6098 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6099 cfg.dir = 0;
6100 cfg.timeout = 0;
6101 if (mpt_config(ioc, &cfg) != 0)
6102 return;
6103
6104 if (header.PageLength == 0)
6105 return;
6106
6107 /* Read Header good, alloc memory
6108 */
6109 iocpage1sz = header.PageLength * 4;
6110 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
6111 if (!pIoc1)
6112 return;
6113
6114 /* Read the Page and check coalescing timeout
6115 */
6116 cfg.physAddr = ioc1_dma;
6117 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6118 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306119
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
6121 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
6122 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
6123
Prakash, Sathya436ace72007-07-24 15:42:08 +05306124 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006125 ioc->name, tmp));
6126
6127 if (tmp > MPT_COALESCING_TIMEOUT) {
6128 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
6129
6130 /* Write NVRAM and current
6131 */
6132 cfg.dir = 1;
6133 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
6134 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306135 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006136 ioc->name, MPT_COALESCING_TIMEOUT));
6137
6138 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
6139 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306140 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6141 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006142 ioc->name, MPT_COALESCING_TIMEOUT));
6143 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306144 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6145 "Reset NVRAM Coalescing Timeout Failed\n",
6146 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006147 }
6148
6149 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306150 dprintk(ioc, printk(MYIOC_s_WARN_FMT
6151 "Reset of Current Coalescing Timeout Failed!\n",
6152 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006153 }
6154 }
6155
6156 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306157 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006158 }
6159 }
6160
6161 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
6162
6163 return;
6164}
6165
Prakash, Sathyaedb90682007-07-17 14:39:14 +05306166static void
6167mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
6168{
6169 CONFIGPARMS cfg;
6170 ConfigPageHeader_t hdr;
6171 dma_addr_t buf_dma;
6172 ManufacturingPage0_t *pbuf = NULL;
6173
6174 memset(&cfg, 0 , sizeof(CONFIGPARMS));
6175 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
6176
6177 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
6178 cfg.cfghdr.hdr = &hdr;
6179 cfg.physAddr = -1;
6180 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6181 cfg.timeout = 10;
6182
6183 if (mpt_config(ioc, &cfg) != 0)
6184 goto out;
6185
6186 if (!cfg.cfghdr.hdr->PageLength)
6187 goto out;
6188
6189 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6190 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
6191 if (!pbuf)
6192 goto out;
6193
6194 cfg.physAddr = buf_dma;
6195
6196 if (mpt_config(ioc, &cfg) != 0)
6197 goto out;
6198
6199 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
6200 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
6201 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
6202
6203 out:
6204
6205 if (pbuf)
6206 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
6207}
6208
Linus Torvalds1da177e2005-04-16 15:20:36 -07006209/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006210/**
6211 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006212 * @ioc: Pointer to MPT_ADAPTER structure
6213 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05306214 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07006215 */
6216static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05306217SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006218{
Kashyap, Desaifd761752009-05-29 16:39:06 +05306219 EventNotification_t evn;
6220 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006221
Kashyap, Desaifd761752009-05-29 16:39:06 +05306222 memset(&evn, 0, sizeof(EventNotification_t));
6223 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006224
Kashyap, Desaifd761752009-05-29 16:39:06 +05306225 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
6226 evn.Switch = EvSwitch;
6227 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228
Kashyap, Desaifd761752009-05-29 16:39:06 +05306229 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6230 "Sending EventNotification (%d) request %p\n",
6231 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006232
Kashyap, Desaifd761752009-05-29 16:39:06 +05306233 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6234 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6235 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006236}
6237
6238/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6239/**
6240 * SendEventAck - Send EventAck request to MPT adapter.
6241 * @ioc: Pointer to MPT_ADAPTER structure
6242 * @evnp: Pointer to original EventNotification request
6243 */
6244static int
6245SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6246{
6247 EventAck_t *pAck;
6248
6249 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306250 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306251 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006252 return -1;
6253 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006254
Prakash, Sathya436ace72007-07-24 15:42:08 +05306255 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006256
6257 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6258 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006259 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006260 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006261 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006262 pAck->Event = evnp->Event;
6263 pAck->EventContext = evnp->EventContext;
6264
6265 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6266
6267 return 0;
6268}
6269
6270/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6271/**
6272 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006273 * @ioc: Pointer to an adapter structure
6274 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006275 * action, page address, direction, physical address
6276 * and pointer to a configuration page header
6277 * Page header is updated.
6278 *
6279 * Returns 0 for success
6280 * -EPERM if not allowed due to ISR context
6281 * -EAGAIN if no msg frames currently available
6282 * -EFAULT for non-successful reply or no reply (timeout)
6283 */
6284int
6285mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6286{
6287 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306288 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006289 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006290 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306291 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006292 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306293 long timeout;
6294 int ret;
6295 u8 page_type = 0, extend_page;
6296 unsigned long timeleft;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306297 unsigned long flags;
6298 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306299 u8 issue_hard_reset = 0;
6300 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006301
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006302 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006303 * to be in ISR context, because that is fatal!
6304 */
6305 in_isr = in_interrupt();
6306 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306307 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006308 ioc->name));
6309 return -EPERM;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306310 }
6311
6312 /* don't send a config page during diag reset */
6313 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6314 if (ioc->ioc_reset_in_progress) {
6315 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6316 "%s: busy with host reset\n", ioc->name, __func__));
6317 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6318 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006319 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306320 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006321
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306322 /* don't send if no chance of success */
6323 if (!ioc->active ||
6324 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6325 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6326 "%s: ioc not operational, %d, %xh\n",
6327 ioc->name, __func__, ioc->active,
6328 mpt_GetIocState(ioc, 0)));
6329 return -EFAULT;
6330 }
6331
6332 retry_config:
6333 mutex_lock(&ioc->mptbase_cmds.mutex);
6334 /* init the internal cmd struct */
6335 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6336 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6337
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338 /* Get and Populate a free Frame
6339 */
6340 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306341 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6342 "mpt_config: no msg frames!\n", ioc->name));
6343 ret = -EAGAIN;
6344 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006345 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306346
Linus Torvalds1da177e2005-04-16 15:20:36 -07006347 pReq = (Config_t *)mf;
6348 pReq->Action = pCfg->action;
6349 pReq->Reserved = 0;
6350 pReq->ChainOffset = 0;
6351 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006352
6353 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006354 pReq->ExtPageLength = 0;
6355 pReq->ExtPageType = 0;
6356 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006357
Linus Torvalds1da177e2005-04-16 15:20:36 -07006358 for (ii=0; ii < 8; ii++)
6359 pReq->Reserved2[ii] = 0;
6360
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006361 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6362 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6363 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6364 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6365
6366 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6367 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6368 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6369 pReq->ExtPageType = pExtHdr->ExtPageType;
6370 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6371
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306372 /* Page Length must be treated as a reserved field for the
6373 * extended header.
6374 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006375 pReq->Header.PageLength = 0;
6376 }
6377
Linus Torvalds1da177e2005-04-16 15:20:36 -07006378 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6379
6380 /* Add a SGE to the config request.
6381 */
6382 if (pCfg->dir)
6383 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6384 else
6385 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6386
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306387 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6388 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006389 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306390 page_type = pReq->ExtPageType;
6391 extend_page = 1;
6392 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006393 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306394 page_type = pReq->Header.PageType;
6395 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006397
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306398 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6399 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6400 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6401
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306402 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306403 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006404 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306405 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6406 timeout);
6407 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6408 ret = -ETIME;
6409 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6410 "Failed Sending Config request type 0x%x, page 0x%x,"
6411 " action %d, status %xh, time left %ld\n\n",
6412 ioc->name, page_type, pReq->Header.PageNumber,
6413 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6414 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6415 goto out;
6416 if (!timeleft)
6417 issue_hard_reset = 1;
6418 goto out;
6419 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006420
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306421 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6422 ret = -1;
6423 goto out;
6424 }
6425 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6426 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6427 if (ret == MPI_IOCSTATUS_SUCCESS) {
6428 if (extend_page) {
6429 pCfg->cfghdr.ehdr->ExtPageLength =
6430 le16_to_cpu(pReply->ExtPageLength);
6431 pCfg->cfghdr.ehdr->ExtPageType =
6432 pReply->ExtPageType;
6433 }
6434 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6435 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6436 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6437 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006438
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306439 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006440
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306441 if (retry_count)
6442 printk(MYIOC_s_INFO_FMT "Retry completed "
6443 "ret=0x%x timeleft=%ld\n",
6444 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006445
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306446 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6447 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006448
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306449out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006450
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306451 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6452 mutex_unlock(&ioc->mptbase_cmds.mutex);
6453 if (issue_hard_reset) {
6454 issue_hard_reset = 0;
Kei Tokunaga97009a22010-06-22 19:01:51 +09006455 printk(MYIOC_s_WARN_FMT
6456 "Issuing Reset from %s!!, doorbell=0x%08x\n",
6457 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaib3b97312010-03-18 19:14:51 +05306458 if (retry_count == 0) {
6459 if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0)
6460 retry_count++;
6461 } else
6462 mpt_HardResetHandler(ioc, CAN_SLEEP);
6463
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306464 mpt_free_msg_frame(ioc, mf);
6465 /* attempt one retry for a timed out command */
Kashyap, Desaib3b97312010-03-18 19:14:51 +05306466 if (retry_count < 2) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306467 printk(MYIOC_s_INFO_FMT
6468 "Attempting Retry Config request"
6469 " type 0x%x, page 0x%x,"
6470 " action %d\n", ioc->name, page_type,
6471 pCfg->cfghdr.hdr->PageNumber, pCfg->action);
6472 retry_count++;
6473 goto retry_config;
6474 }
6475 }
6476 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006477
Linus Torvalds1da177e2005-04-16 15:20:36 -07006478}
6479
6480/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006481/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006482 * mpt_ioc_reset - Base cleanup for hard reset
6483 * @ioc: Pointer to the adapter structure
6484 * @reset_phase: Indicates pre- or post-reset functionality
6485 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006486 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006487 */
6488static int
6489mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6490{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306491 switch (reset_phase) {
6492 case MPT_IOC_SETUP_RESET:
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306493 ioc->taskmgmt_quiesce_io = 1;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306494 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6495 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
6496 break;
6497 case MPT_IOC_PRE_RESET:
6498 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6499 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
6500 break;
6501 case MPT_IOC_POST_RESET:
6502 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6503 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
6504/* wake up mptbase_cmds */
6505 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6506 ioc->mptbase_cmds.status |=
6507 MPT_MGMT_STATUS_DID_IOCRESET;
6508 complete(&ioc->mptbase_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006509 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306510/* wake up taskmgmt_cmds */
6511 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
6512 ioc->taskmgmt_cmds.status |=
6513 MPT_MGMT_STATUS_DID_IOCRESET;
6514 complete(&ioc->taskmgmt_cmds.done);
6515 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306516 break;
6517 default:
6518 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006519 }
6520
6521 return 1; /* currently means nothing really */
6522}
6523
6524
6525#ifdef CONFIG_PROC_FS /* { */
6526/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6527/*
6528 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6529 */
6530/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006531/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006532 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6533 *
6534 * Returns 0 for success, non-zero for failure.
6535 */
6536static int
6537procmpt_create(void)
6538{
Linus Torvalds1da177e2005-04-16 15:20:36 -07006539 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6540 if (mpt_proc_root_dir == NULL)
6541 return -ENOTDIR;
6542
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006543 proc_create("summary", S_IRUGO, mpt_proc_root_dir, &mpt_summary_proc_fops);
6544 proc_create("version", S_IRUGO, mpt_proc_root_dir, &mpt_version_proc_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006545 return 0;
6546}
6547
6548/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006549/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006550 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6551 *
6552 * Returns 0 for success, non-zero for failure.
6553 */
6554static void
6555procmpt_destroy(void)
6556{
6557 remove_proc_entry("version", mpt_proc_root_dir);
6558 remove_proc_entry("summary", mpt_proc_root_dir);
6559 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6560}
6561
6562/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlap1f5cfe22010-08-14 13:05:50 -07006563/*
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006564 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006565 */
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006566static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan);
6567
6568static int mpt_summary_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006569{
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006570 MPT_ADAPTER *ioc = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006571
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006572 if (ioc) {
6573 seq_mpt_print_ioc_summary(ioc, m, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006574 } else {
6575 list_for_each_entry(ioc, &ioc_list, list) {
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006576 seq_mpt_print_ioc_summary(ioc, m, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006577 }
6578 }
6579
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006580 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006581}
6582
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006583static int mpt_summary_proc_open(struct inode *inode, struct file *file)
6584{
6585 return single_open(file, mpt_summary_proc_show, PDE(inode)->data);
6586}
6587
6588static const struct file_operations mpt_summary_proc_fops = {
6589 .owner = THIS_MODULE,
6590 .open = mpt_summary_proc_open,
6591 .read = seq_read,
6592 .llseek = seq_lseek,
6593 .release = single_release,
6594};
6595
6596static int mpt_version_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006597{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306598 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006599 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006600 char *drvname;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006601
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006602 seq_printf(m, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6603 seq_printf(m, " Fusion MPT base driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006604
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006605 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006606 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006607 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306608 if (MptCallbacks[cb_idx]) {
6609 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006610 case MPTSPI_DRIVER:
6611 if (!scsi++) drvname = "SPI host";
6612 break;
6613 case MPTFC_DRIVER:
6614 if (!fc++) drvname = "FC host";
6615 break;
6616 case MPTSAS_DRIVER:
6617 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006618 break;
6619 case MPTLAN_DRIVER:
6620 if (!lan++) drvname = "LAN";
6621 break;
6622 case MPTSTM_DRIVER:
6623 if (!targ++) drvname = "SCSI target";
6624 break;
6625 case MPTCTL_DRIVER:
6626 if (!ctl++) drvname = "ioctl";
6627 break;
6628 }
6629
6630 if (drvname)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006631 seq_printf(m, " Fusion MPT %s driver\n", drvname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006632 }
6633 }
6634
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006635 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006636}
6637
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006638static int mpt_version_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006639{
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006640 return single_open(file, mpt_version_proc_show, NULL);
6641}
6642
6643static const struct file_operations mpt_version_proc_fops = {
6644 .owner = THIS_MODULE,
6645 .open = mpt_version_proc_open,
6646 .read = seq_read,
6647 .llseek = seq_lseek,
6648 .release = single_release,
6649};
6650
6651static int mpt_iocinfo_proc_show(struct seq_file *m, void *v)
6652{
6653 MPT_ADAPTER *ioc = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006654 char expVer[32];
6655 int sz;
6656 int p;
6657
6658 mpt_get_fw_exp_ver(expVer, ioc);
6659
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006660 seq_printf(m, "%s:", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006661 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006662 seq_printf(m, " (f/w download boot flag set)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006663// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006664// seq_printf(m, " CONFIG_CHECKSUM_FAIL!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006665
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006666 seq_printf(m, "\n ProductID = 0x%04x (%s)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006667 ioc->facts.ProductID,
6668 ioc->prod_name);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006669 seq_printf(m, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006670 if (ioc->facts.FWImageSize)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006671 seq_printf(m, " (fw_size=%d)", ioc->facts.FWImageSize);
6672 seq_printf(m, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6673 seq_printf(m, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6674 seq_printf(m, " EventState = 0x%02x\n", ioc->facts.EventState);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006675
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006676 seq_printf(m, " CurrentHostMfaHighAddr = 0x%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006677 ioc->facts.CurrentHostMfaHighAddr);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006678 seq_printf(m, " CurrentSenseBufferHighAddr = 0x%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006679 ioc->facts.CurrentSenseBufferHighAddr);
6680
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006681 seq_printf(m, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6682 seq_printf(m, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006683
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006684 seq_printf(m, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006685 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6686 /*
6687 * Rounding UP to nearest 4-kB boundary here...
6688 */
6689 sz = (ioc->req_sz * ioc->req_depth) + 128;
6690 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006691 seq_printf(m, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006692 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006693 seq_printf(m, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006694 4*ioc->facts.RequestFrameSize,
6695 ioc->facts.GlobalCredits);
6696
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006697 seq_printf(m, " Frames @ 0x%p (Dma @ 0x%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006698 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6699 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006700 seq_printf(m, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006701 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006702 seq_printf(m, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006703 ioc->facts.CurReplyFrameSize,
6704 ioc->facts.ReplyQueueDepth);
6705
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006706 seq_printf(m, " MaxDevices = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006707 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006708 seq_printf(m, " MaxBuses = %d\n", ioc->facts.MaxBuses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006709
6710 /* per-port info */
6711 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006712 seq_printf(m, " PortNumber = %d (of %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006713 p+1,
6714 ioc->facts.NumberOfPorts);
6715 if (ioc->bus_type == FC) {
6716 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6717 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006718 seq_printf(m, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006719 a[5], a[4], a[3], a[2], a[1], a[0]);
6720 }
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006721 seq_printf(m, " WWN = %08X%08X:%08X%08X\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006722 ioc->fc_port_page0[p].WWNN.High,
6723 ioc->fc_port_page0[p].WWNN.Low,
6724 ioc->fc_port_page0[p].WWPN.High,
6725 ioc->fc_port_page0[p].WWPN.Low);
6726 }
6727 }
6728
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006729 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006730}
6731
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006732static int mpt_iocinfo_proc_open(struct inode *inode, struct file *file)
6733{
6734 return single_open(file, mpt_iocinfo_proc_show, PDE(inode)->data);
6735}
6736
6737static const struct file_operations mpt_iocinfo_proc_fops = {
6738 .owner = THIS_MODULE,
6739 .open = mpt_iocinfo_proc_open,
6740 .read = seq_read,
6741 .llseek = seq_lseek,
6742 .release = single_release,
6743};
Linus Torvalds1da177e2005-04-16 15:20:36 -07006744#endif /* CONFIG_PROC_FS } */
6745
6746/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6747static void
6748mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6749{
6750 buf[0] ='\0';
6751 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6752 sprintf(buf, " (Exp %02d%02d)",
6753 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6754 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6755
6756 /* insider hack! */
6757 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6758 strcat(buf, " [MDBG]");
6759 }
6760}
6761
6762/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6763/**
6764 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6765 * @ioc: Pointer to MPT_ADAPTER structure
6766 * @buffer: Pointer to buffer where IOC summary info should be written
6767 * @size: Pointer to number of bytes we wrote (set by this routine)
6768 * @len: Offset at which to start writing in buffer
6769 * @showlan: Display LAN stuff?
6770 *
6771 * This routine writes (english readable) ASCII text, which represents
6772 * a summary of IOC information, to a buffer.
6773 */
6774void
6775mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6776{
6777 char expVer[32];
6778 int y;
6779
6780 mpt_get_fw_exp_ver(expVer, ioc);
6781
6782 /*
6783 * Shorter summary of attached ioc's...
6784 */
6785 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6786 ioc->name,
6787 ioc->prod_name,
6788 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6789 ioc->facts.FWVersion.Word,
6790 expVer,
6791 ioc->facts.NumberOfPorts,
6792 ioc->req_depth);
6793
6794 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6795 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6796 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6797 a[5], a[4], a[3], a[2], a[1], a[0]);
6798 }
6799
Linus Torvalds1da177e2005-04-16 15:20:36 -07006800 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006801
6802 if (!ioc->active)
6803 y += sprintf(buffer+len+y, " (disabled)");
6804
6805 y += sprintf(buffer+len+y, "\n");
6806
6807 *size = y;
6808}
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006809
6810static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan)
6811{
6812 char expVer[32];
6813
6814 mpt_get_fw_exp_ver(expVer, ioc);
6815
6816 /*
6817 * Shorter summary of attached ioc's...
6818 */
6819 seq_printf(m, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6820 ioc->name,
6821 ioc->prod_name,
6822 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6823 ioc->facts.FWVersion.Word,
6824 expVer,
6825 ioc->facts.NumberOfPorts,
6826 ioc->req_depth);
6827
6828 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6829 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6830 seq_printf(m, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6831 a[5], a[4], a[3], a[2], a[1], a[0]);
6832 }
6833
6834 seq_printf(m, ", IRQ=%d", ioc->pci_irq);
6835
6836 if (!ioc->active)
6837 seq_printf(m, " (disabled)");
6838
6839 seq_putc(m, '\n');
6840}
6841
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306842/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006843 * mpt_set_taskmgmt_in_progress_flag - set flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306844 * @ioc: Pointer to MPT_ADAPTER structure
6845 *
6846 * Returns 0 for SUCCESS or -1 if FAILED.
6847 *
6848 * If -1 is return, then it was not possible to set the flags
6849 **/
6850int
6851mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6852{
6853 unsigned long flags;
6854 int retval;
6855
6856 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6857 if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
6858 (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
6859 retval = -1;
6860 goto out;
6861 }
6862 retval = 0;
6863 ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306864 ioc->taskmgmt_quiesce_io = 1;
6865 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306866 ioc->alt_ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306867 ioc->alt_ioc->taskmgmt_quiesce_io = 1;
6868 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306869 out:
6870 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6871 return retval;
6872}
6873EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
6874
6875/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006876 * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306877 * @ioc: Pointer to MPT_ADAPTER structure
6878 *
6879 **/
6880void
6881mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6882{
6883 unsigned long flags;
6884
6885 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6886 ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306887 ioc->taskmgmt_quiesce_io = 0;
6888 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306889 ioc->alt_ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306890 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
6891 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306892 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6893}
6894EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006895
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306896
6897/**
6898 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6899 * the kernel
6900 * @ioc: Pointer to MPT_ADAPTER structure
6901 *
6902 **/
6903void
6904mpt_halt_firmware(MPT_ADAPTER *ioc)
6905{
6906 u32 ioc_raw_state;
6907
6908 ioc_raw_state = mpt_GetIocState(ioc, 0);
6909
6910 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6911 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6912 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6913 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6914 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6915 } else {
6916 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6917 panic("%s: Firmware is halted due to command timeout\n",
6918 ioc->name);
6919 }
6920}
6921EXPORT_SYMBOL(mpt_halt_firmware);
6922
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306923/**
6924 * mpt_SoftResetHandler - Issues a less expensive reset
6925 * @ioc: Pointer to MPT_ADAPTER structure
6926 * @sleepFlag: Indicates if sleep or schedule must be called.
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306927 *
6928 * Returns 0 for SUCCESS or -1 if FAILED.
6929 *
6930 * Message Unit Reset - instructs the IOC to reset the Reply Post and
6931 * Free FIFO's. All the Message Frames on Reply Free FIFO are discarded.
6932 * All posted buffers are freed, and event notification is turned off.
Lucas De Marchi25985ed2011-03-30 22:57:33 -03006933 * IOC doesn't reply to any outstanding request. This will transfer IOC
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306934 * to READY state.
6935 **/
6936int
6937mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6938{
6939 int rc;
6940 int ii;
6941 u8 cb_idx;
6942 unsigned long flags;
6943 u32 ioc_state;
6944 unsigned long time_count;
6945
6946 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n",
6947 ioc->name));
6948
6949 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
6950
6951 if (mpt_fwfault_debug)
6952 mpt_halt_firmware(ioc);
6953
6954 if (ioc_state == MPI_IOC_STATE_FAULT ||
6955 ioc_state == MPI_IOC_STATE_RESET) {
6956 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6957 "skipping, either in FAULT or RESET state!\n", ioc->name));
6958 return -1;
6959 }
6960
6961 if (ioc->bus_type == FC) {
6962 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6963 "skipping, because the bus type is FC!\n", ioc->name));
6964 return -1;
6965 }
6966
6967 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6968 if (ioc->ioc_reset_in_progress) {
6969 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6970 return -1;
6971 }
6972 ioc->ioc_reset_in_progress = 1;
6973 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6974
6975 rc = -1;
6976
6977 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6978 if (MptResetHandlers[cb_idx])
6979 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
6980 }
6981
6982 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6983 if (ioc->taskmgmt_in_progress) {
Kashyap, Desaib9a0f872010-06-17 14:42:39 +05306984 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306985 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6986 return -1;
6987 }
6988 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6989 /* Disable reply interrupts (also blocks FreeQ) */
6990 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
6991 ioc->active = 0;
6992 time_count = jiffies;
6993
6994 rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
6995
6996 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6997 if (MptResetHandlers[cb_idx])
6998 mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
6999 }
7000
7001 if (rc)
7002 goto out;
7003
7004 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
7005 if (ioc_state != MPI_IOC_STATE_READY)
7006 goto out;
7007
7008 for (ii = 0; ii < 5; ii++) {
7009 /* Get IOC facts! Allow 5 retries */
7010 rc = GetIocFacts(ioc, sleepFlag,
7011 MPT_HOSTEVENT_IOC_RECOVER);
7012 if (rc == 0)
7013 break;
7014 if (sleepFlag == CAN_SLEEP)
7015 msleep(100);
7016 else
7017 mdelay(100);
7018 }
7019 if (ii == 5)
7020 goto out;
7021
7022 rc = PrimeIocFifos(ioc);
7023 if (rc != 0)
7024 goto out;
7025
7026 rc = SendIocInit(ioc, sleepFlag);
7027 if (rc != 0)
7028 goto out;
7029
7030 rc = SendEventNotification(ioc, 1, sleepFlag);
7031 if (rc != 0)
7032 goto out;
7033
7034 if (ioc->hard_resets < -1)
7035 ioc->hard_resets++;
7036
7037 /*
7038 * At this point, we know soft reset succeeded.
7039 */
7040
7041 ioc->active = 1;
7042 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
7043
7044 out:
7045 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7046 ioc->ioc_reset_in_progress = 0;
7047 ioc->taskmgmt_quiesce_io = 0;
7048 ioc->taskmgmt_in_progress = 0;
7049 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7050
7051 if (ioc->active) { /* otherwise, hard reset coming */
7052 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7053 if (MptResetHandlers[cb_idx])
7054 mpt_signal_reset(cb_idx, ioc,
7055 MPT_IOC_POST_RESET);
7056 }
7057 }
7058
7059 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7060 "SoftResetHandler: completed (%d seconds): %s\n",
7061 ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,
7062 ((rc == 0) ? "SUCCESS" : "FAILED")));
7063
7064 return rc;
7065}
7066
7067/**
7068 * mpt_Soft_Hard_ResetHandler - Try less expensive reset
7069 * @ioc: Pointer to MPT_ADAPTER structure
7070 * @sleepFlag: Indicates if sleep or schedule must be called.
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05307071 *
7072 * Returns 0 for SUCCESS or -1 if FAILED.
7073 * Try for softreset first, only if it fails go for expensive
7074 * HardReset.
7075 **/
7076int
7077mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag) {
7078 int ret = -1;
7079
7080 ret = mpt_SoftResetHandler(ioc, sleepFlag);
7081 if (ret == 0)
7082 return ret;
7083 ret = mpt_HardResetHandler(ioc, sleepFlag);
7084 return ret;
7085}
7086EXPORT_SYMBOL(mpt_Soft_Hard_ResetHandler);
7087
Linus Torvalds1da177e2005-04-16 15:20:36 -07007088/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7089/*
7090 * Reset Handling
7091 */
7092/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7093/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007094 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07007095 * @ioc: Pointer to MPT_ADAPTER structure
7096 * @sleepFlag: Indicates if sleep or schedule must be called.
7097 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007098 * Issues SCSI Task Management call based on input arg values.
7099 * If TaskMgmt fails, returns associated SCSI request.
7100 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07007101 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
7102 * or a non-interrupt thread. In the former, must not call schedule().
7103 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007104 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07007105 * FW reload/initialization failed.
7106 *
7107 * Returns 0 for SUCCESS or -1 if FAILED.
7108 */
7109int
7110mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
7111{
Kashyap, Desaid1306912009-08-05 12:53:51 +05307112 int rc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307113 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007114 unsigned long flags;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307115 unsigned long time_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007116
Prakash, Sathya436ace72007-07-24 15:42:08 +05307117 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007118#ifdef MFCNT
7119 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
7120 printk("MF count 0x%x !\n", ioc->mfcnt);
7121#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05307122 if (mpt_fwfault_debug)
7123 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007124
7125 /* Reset the adapter. Prevent more than 1 call to
7126 * mpt_do_ioc_recovery at any instant in time.
7127 */
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307128 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7129 if (ioc->ioc_reset_in_progress) {
7130 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007131 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007132 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307133 ioc->ioc_reset_in_progress = 1;
7134 if (ioc->alt_ioc)
7135 ioc->alt_ioc->ioc_reset_in_progress = 1;
7136 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007137
Linus Torvalds1da177e2005-04-16 15:20:36 -07007138
7139 /* The SCSI driver needs to adjust timeouts on all current
7140 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02007141 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007142 * For all other protocol drivers, this is a no-op.
7143 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05307144 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7145 if (MptResetHandlers[cb_idx]) {
7146 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
7147 if (ioc->alt_ioc)
7148 mpt_signal_reset(cb_idx, ioc->alt_ioc,
7149 MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007150 }
7151 }
7152
Kashyap, Desai2f187862009-05-29 16:52:37 +05307153 time_count = jiffies;
7154 rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
7155 if (rc != 0) {
7156 printk(KERN_WARNING MYNAM
Kei Tokunaga97009a22010-06-22 19:01:51 +09007157 ": WARNING - (%d) Cannot recover %s, doorbell=0x%08x\n",
7158 rc, ioc->name, mpt_GetIocState(ioc, 0));
Kashyap, Desai2f187862009-05-29 16:52:37 +05307159 } else {
7160 if (ioc->hard_resets < -1)
7161 ioc->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007162 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007163
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307164 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7165 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307166 ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307167 ioc->taskmgmt_in_progress = 0;
7168 if (ioc->alt_ioc) {
7169 ioc->alt_ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307170 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307171 ioc->alt_ioc->taskmgmt_in_progress = 0;
7172 }
7173 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007174
Kashyap, Desaid1306912009-08-05 12:53:51 +05307175 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7176 if (MptResetHandlers[cb_idx]) {
7177 mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
7178 if (ioc->alt_ioc)
7179 mpt_signal_reset(cb_idx,
7180 ioc->alt_ioc, MPT_IOC_POST_RESET);
7181 }
7182 }
7183
Kashyap, Desai2f187862009-05-29 16:52:37 +05307184 dtmprintk(ioc,
7185 printk(MYIOC_s_DEBUG_FMT
7186 "HardResetHandler: completed (%d seconds): %s\n", ioc->name,
7187 jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?
7188 "SUCCESS" : "FAILED")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007189
7190 return rc;
7191}
7192
Kashyap, Desai2f187862009-05-29 16:52:37 +05307193#ifdef CONFIG_FUSION_LOGGING
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007194static void
Kashyap, Desai2f187862009-05-29 16:52:37 +05307195mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007196{
Eric Moore509e5e52006-04-26 13:22:37 -06007197 char *ds = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307198 u32 evData0;
7199 int ii;
7200 u8 event;
7201 char *evStr = ioc->evStr;
7202
7203 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7204 evData0 = le32_to_cpu(pEventReply->Data[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007205
7206 switch(event) {
7207 case MPI_EVENT_NONE:
7208 ds = "None";
7209 break;
7210 case MPI_EVENT_LOG_DATA:
7211 ds = "Log Data";
7212 break;
7213 case MPI_EVENT_STATE_CHANGE:
7214 ds = "State Change";
7215 break;
7216 case MPI_EVENT_UNIT_ATTENTION:
7217 ds = "Unit Attention";
7218 break;
7219 case MPI_EVENT_IOC_BUS_RESET:
7220 ds = "IOC Bus Reset";
7221 break;
7222 case MPI_EVENT_EXT_BUS_RESET:
7223 ds = "External Bus Reset";
7224 break;
7225 case MPI_EVENT_RESCAN:
7226 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007227 break;
7228 case MPI_EVENT_LINK_STATUS_CHANGE:
7229 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
7230 ds = "Link Status(FAILURE) Change";
7231 else
7232 ds = "Link Status(ACTIVE) Change";
7233 break;
7234 case MPI_EVENT_LOOP_STATE_CHANGE:
7235 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
7236 ds = "Loop State(LIP) Change";
7237 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Kashyap, Desai2f187862009-05-29 16:52:37 +05307238 ds = "Loop State(LPE) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007239 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05307240 ds = "Loop State(LPB) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007241 break;
7242 case MPI_EVENT_LOGOUT:
7243 ds = "Logout";
7244 break;
7245 case MPI_EVENT_EVENT_CHANGE:
7246 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06007247 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007248 else
Eric Moore4f766dc2006-07-11 17:24:07 -06007249 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007250 break;
7251 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007252 {
7253 u8 ReasonCode = (u8)(evData0 >> 16);
7254 switch (ReasonCode) {
7255 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
7256 ds = "Integrated Raid: Volume Created";
7257 break;
7258 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
7259 ds = "Integrated Raid: Volume Deleted";
7260 break;
7261 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
7262 ds = "Integrated Raid: Volume Settings Changed";
7263 break;
7264 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
7265 ds = "Integrated Raid: Volume Status Changed";
7266 break;
7267 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
7268 ds = "Integrated Raid: Volume Physdisk Changed";
7269 break;
7270 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
7271 ds = "Integrated Raid: Physdisk Created";
7272 break;
7273 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
7274 ds = "Integrated Raid: Physdisk Deleted";
7275 break;
7276 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
7277 ds = "Integrated Raid: Physdisk Settings Changed";
7278 break;
7279 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
7280 ds = "Integrated Raid: Physdisk Status Changed";
7281 break;
7282 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
7283 ds = "Integrated Raid: Domain Validation Needed";
7284 break;
7285 case MPI_EVENT_RAID_RC_SMART_DATA :
7286 ds = "Integrated Raid; Smart Data";
7287 break;
7288 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
7289 ds = "Integrated Raid: Replace Action Started";
7290 break;
7291 default:
7292 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007293 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007294 }
7295 break;
7296 }
7297 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
7298 ds = "SCSI Device Status Change";
7299 break;
7300 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
7301 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007302 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007303 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007304 u8 ReasonCode = (u8)(evData0 >> 16);
7305 switch (ReasonCode) {
7306 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007307 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007308 "SAS Device Status Change: Added: "
7309 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007310 break;
7311 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06007312 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007313 "SAS Device Status Change: Deleted: "
7314 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007315 break;
7316 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06007317 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007318 "SAS Device Status Change: SMART Data: "
7319 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007320 break;
7321 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007322 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007323 "SAS Device Status Change: No Persistancy: "
7324 "id=%d channel=%d", id, channel);
7325 break;
7326 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
7327 snprintf(evStr, EVENT_DESCR_STR_SZ,
7328 "SAS Device Status Change: Unsupported Device "
7329 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007330 break;
7331 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
7332 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007333 "SAS Device Status Change: Internal Device "
7334 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007335 break;
7336 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
7337 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007338 "SAS Device Status Change: Internal Task "
7339 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007340 break;
7341 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
7342 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007343 "SAS Device Status Change: Internal Abort "
7344 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007345 break;
7346 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
7347 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007348 "SAS Device Status Change: Internal Clear "
7349 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007350 break;
7351 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
7352 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007353 "SAS Device Status Change: Internal Query "
7354 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007355 break;
7356 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007357 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007358 "SAS Device Status Change: Unknown: "
7359 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06007360 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007361 }
7362 break;
7363 }
7364 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
7365 ds = "Bus Timer Expired";
7366 break;
7367 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07007368 {
7369 u16 curr_depth = (u16)(evData0 >> 16);
7370 u8 channel = (u8)(evData0 >> 8);
7371 u8 id = (u8)(evData0);
7372
7373 snprintf(evStr, EVENT_DESCR_STR_SZ,
7374 "Queue Full: channel=%d id=%d depth=%d",
7375 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007376 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07007377 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007378 case MPI_EVENT_SAS_SES:
7379 ds = "SAS SES Event";
7380 break;
7381 case MPI_EVENT_PERSISTENT_TABLE_FULL:
7382 ds = "Persistent Table Full";
7383 break;
7384 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07007385 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007386 u8 LinkRates = (u8)(evData0 >> 8);
7387 u8 PhyNumber = (u8)(evData0);
7388 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
7389 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
7390 switch (LinkRates) {
7391 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06007392 snprintf(evStr, EVENT_DESCR_STR_SZ,
7393 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007394 " Rate Unknown",PhyNumber);
7395 break;
7396 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06007397 snprintf(evStr, EVENT_DESCR_STR_SZ,
7398 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007399 " Phy Disabled",PhyNumber);
7400 break;
7401 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06007402 snprintf(evStr, EVENT_DESCR_STR_SZ,
7403 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007404 " Failed Speed Nego",PhyNumber);
7405 break;
7406 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06007407 snprintf(evStr, EVENT_DESCR_STR_SZ,
7408 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007409 " Sata OOB Completed",PhyNumber);
7410 break;
7411 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06007412 snprintf(evStr, EVENT_DESCR_STR_SZ,
7413 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007414 " Rate 1.5 Gbps",PhyNumber);
7415 break;
7416 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06007417 snprintf(evStr, EVENT_DESCR_STR_SZ,
7418 "SAS PHY Link Status: Phy=%d:"
Kashyap, Desaid75733d2011-02-10 11:50:39 +05307419 " Rate 3.0 Gbps", PhyNumber);
7420 break;
7421 case MPI_EVENT_SAS_PLS_LR_RATE_6_0:
7422 snprintf(evStr, EVENT_DESCR_STR_SZ,
7423 "SAS PHY Link Status: Phy=%d:"
7424 " Rate 6.0 Gbps", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007425 break;
7426 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007427 snprintf(evStr, EVENT_DESCR_STR_SZ,
7428 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007429 break;
7430 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007431 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007432 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007433 case MPI_EVENT_SAS_DISCOVERY_ERROR:
7434 ds = "SAS Discovery Error";
7435 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007436 case MPI_EVENT_IR_RESYNC_UPDATE:
7437 {
7438 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06007439 snprintf(evStr, EVENT_DESCR_STR_SZ,
7440 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07007441 break;
7442 }
7443 case MPI_EVENT_IR2:
7444 {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307445 u8 id = (u8)(evData0);
7446 u8 channel = (u8)(evData0 >> 8);
7447 u8 phys_num = (u8)(evData0 >> 24);
Moore, Eric3a892be2006-03-14 09:14:03 -07007448 u8 ReasonCode = (u8)(evData0 >> 16);
Kashyap, Desai2f187862009-05-29 16:52:37 +05307449
Moore, Eric3a892be2006-03-14 09:14:03 -07007450 switch (ReasonCode) {
7451 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307452 snprintf(evStr, EVENT_DESCR_STR_SZ,
7453 "IR2: LD 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_PD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307458 snprintf(evStr, EVENT_DESCR_STR_SZ,
7459 "IR2: PD State Changed "
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_BAD_BLOCK_TABLE_FULL:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307464 snprintf(evStr, EVENT_DESCR_STR_SZ,
7465 "IR2: Bad Block Table Full: "
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_INSERTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307470 snprintf(evStr, EVENT_DESCR_STR_SZ,
7471 "IR2: PD Inserted: "
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_PD_REMOVED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307476 snprintf(evStr, EVENT_DESCR_STR_SZ,
7477 "IR2: PD Removed: "
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_FOREIGN_CFG_DETECTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307482 snprintf(evStr, EVENT_DESCR_STR_SZ,
7483 "IR2: Foreign CFG Detected: "
7484 "id=%d channel=%d phys_num=%d",
7485 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007486 break;
7487 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307488 snprintf(evStr, EVENT_DESCR_STR_SZ,
7489 "IR2: Rebuild Medium Error: "
7490 "id=%d channel=%d phys_num=%d",
7491 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007492 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05307493 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
7494 snprintf(evStr, EVENT_DESCR_STR_SZ,
7495 "IR2: Dual Port Added: "
7496 "id=%d channel=%d phys_num=%d",
7497 id, channel, phys_num);
7498 break;
7499 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
7500 snprintf(evStr, EVENT_DESCR_STR_SZ,
7501 "IR2: Dual Port Removed: "
7502 "id=%d channel=%d phys_num=%d",
7503 id, channel, phys_num);
7504 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007505 default:
7506 ds = "IR2";
7507 break;
7508 }
7509 break;
7510 }
7511 case MPI_EVENT_SAS_DISCOVERY:
7512 {
7513 if (evData0)
7514 ds = "SAS Discovery: Start";
7515 else
7516 ds = "SAS Discovery: Stop";
7517 break;
7518 }
7519 case MPI_EVENT_LOG_ENTRY_ADDED:
7520 ds = "SAS Log Entry Added";
7521 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007522
Eric Moorec6c727a2007-01-29 09:44:54 -07007523 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
7524 {
7525 u8 phy_num = (u8)(evData0);
7526 u8 port_num = (u8)(evData0 >> 8);
7527 u8 port_width = (u8)(evData0 >> 16);
7528 u8 primative = (u8)(evData0 >> 24);
7529 snprintf(evStr, EVENT_DESCR_STR_SZ,
7530 "SAS Broadcase Primative: phy=%d port=%d "
7531 "width=%d primative=0x%02x",
7532 phy_num, port_num, port_width, primative);
7533 break;
7534 }
7535
7536 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7537 {
7538 u8 reason = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007539
Kashyap, Desai2f187862009-05-29 16:52:37 +05307540 switch (reason) {
7541 case MPI_EVENT_SAS_INIT_RC_ADDED:
7542 ds = "SAS Initiator Status Change: Added";
7543 break;
7544 case MPI_EVENT_SAS_INIT_RC_REMOVED:
7545 ds = "SAS Initiator Status Change: Deleted";
7546 break;
7547 default:
7548 ds = "SAS Initiator Status Change";
7549 break;
7550 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007551 break;
7552 }
7553
7554 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7555 {
7556 u8 max_init = (u8)(evData0);
7557 u8 current_init = (u8)(evData0 >> 8);
7558
7559 snprintf(evStr, EVENT_DESCR_STR_SZ,
7560 "SAS Initiator Device Table Overflow: max initiators=%02d "
7561 "current initators=%02d",
7562 max_init, current_init);
7563 break;
7564 }
7565 case MPI_EVENT_SAS_SMP_ERROR:
7566 {
7567 u8 status = (u8)(evData0);
7568 u8 port_num = (u8)(evData0 >> 8);
7569 u8 result = (u8)(evData0 >> 16);
7570
7571 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7572 snprintf(evStr, EVENT_DESCR_STR_SZ,
7573 "SAS SMP Error: port=%d result=0x%02x",
7574 port_num, result);
7575 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7576 snprintf(evStr, EVENT_DESCR_STR_SZ,
7577 "SAS SMP Error: port=%d : CRC Error",
7578 port_num);
7579 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7580 snprintf(evStr, EVENT_DESCR_STR_SZ,
7581 "SAS SMP Error: port=%d : Timeout",
7582 port_num);
7583 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7584 snprintf(evStr, EVENT_DESCR_STR_SZ,
7585 "SAS SMP Error: port=%d : No Destination",
7586 port_num);
7587 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7588 snprintf(evStr, EVENT_DESCR_STR_SZ,
7589 "SAS SMP Error: port=%d : Bad Destination",
7590 port_num);
7591 else
7592 snprintf(evStr, EVENT_DESCR_STR_SZ,
7593 "SAS SMP Error: port=%d : status=0x%02x",
7594 port_num, status);
7595 break;
7596 }
7597
Kashyap, Desai2f187862009-05-29 16:52:37 +05307598 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
7599 {
7600 u8 reason = (u8)(evData0);
7601
7602 switch (reason) {
7603 case MPI_EVENT_SAS_EXP_RC_ADDED:
7604 ds = "Expander Status Change: Added";
7605 break;
7606 case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
7607 ds = "Expander Status Change: Deleted";
7608 break;
7609 default:
7610 ds = "Expander Status Change";
7611 break;
7612 }
7613 break;
7614 }
7615
Linus Torvalds1da177e2005-04-16 15:20:36 -07007616 /*
7617 * MPT base "custom" events may be added here...
7618 */
7619 default:
7620 ds = "Unknown";
7621 break;
7622 }
Eric Moore509e5e52006-04-26 13:22:37 -06007623 if (ds)
7624 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007625
Kashyap, Desai2f187862009-05-29 16:52:37 +05307626
7627 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7628 "MPT event:(%02Xh) : %s\n",
7629 ioc->name, event, evStr));
7630
7631 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
7632 ": Event data:\n"));
7633 for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
7634 devtverboseprintk(ioc, printk(" %08x",
7635 le32_to_cpu(pEventReply->Data[ii])));
7636 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
7637}
7638#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007639/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007640/**
7641 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007642 * @ioc: Pointer to MPT_ADAPTER structure
7643 * @pEventReply: Pointer to EventNotification reply frame
7644 * @evHandlers: Pointer to integer, number of event handlers
7645 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007646 * Routes a received EventNotificationReply to all currently registered
7647 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007648 * Returns sum of event handlers return values.
7649 */
7650static int
7651ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7652{
7653 u16 evDataLen;
7654 u32 evData0 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007655 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307656 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007657 int r = 0;
7658 int handlers = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007659 u8 event;
7660
7661 /*
7662 * Do platform normalization of values
7663 */
7664 event = le32_to_cpu(pEventReply->Event) & 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007665 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7666 if (evDataLen) {
7667 evData0 = le32_to_cpu(pEventReply->Data[0]);
7668 }
7669
Prakash, Sathya436ace72007-07-24 15:42:08 +05307670#ifdef CONFIG_FUSION_LOGGING
Kashyap, Desai2f187862009-05-29 16:52:37 +05307671 if (evDataLen)
7672 mpt_display_event_info(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007673#endif
7674
7675 /*
7676 * Do general / base driver event processing
7677 */
7678 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007679 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7680 if (evDataLen) {
7681 u8 evState = evData0 & 0xFF;
7682
7683 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7684
7685 /* Update EventState field in cached IocFacts */
7686 if (ioc->facts.Function) {
7687 ioc->facts.EventState = evState;
7688 }
7689 }
7690 break;
Moore, Ericece50912006-01-16 18:53:19 -07007691 case MPI_EVENT_INTEGRATED_RAID:
7692 mptbase_raid_process_event_data(ioc,
7693 (MpiEventDataRaid_t *)pEventReply->Data);
7694 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007695 default:
7696 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007697 }
7698
7699 /*
7700 * Should this event be logged? Events are written sequentially.
7701 * When buffer is full, start again at the top.
7702 */
7703 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7704 int idx;
7705
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007706 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007707
7708 ioc->events[idx].event = event;
7709 ioc->events[idx].eventContext = ioc->eventContext;
7710
7711 for (ii = 0; ii < 2; ii++) {
7712 if (ii < evDataLen)
7713 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7714 else
7715 ioc->events[idx].data[ii] = 0;
7716 }
7717
7718 ioc->eventContext++;
7719 }
7720
7721
7722 /*
7723 * Call each currently registered protocol event handler.
7724 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007725 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307726 if (MptEvHandlers[cb_idx]) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307727 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7728 "Routing Event to event handler #%d\n",
7729 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307730 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007731 handlers++;
7732 }
7733 }
7734 /* FIXME? Examine results here? */
7735
7736 /*
7737 * If needed, send (a single) EventAck.
7738 */
7739 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307740 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007741 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007742 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307743 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007744 ioc->name, ii));
7745 }
7746 }
7747
7748 *evHandlers = handlers;
7749 return r;
7750}
7751
7752/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007753/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007754 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7755 * @ioc: Pointer to MPT_ADAPTER structure
7756 * @log_info: U32 LogInfo reply word from the IOC
7757 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007758 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007759 */
7760static void
7761mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7762{
Eric Moore7c431e52007-06-13 16:34:36 -06007763 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007764
Eric Moore7c431e52007-06-13 16:34:36 -06007765 switch (log_info & 0xFF000000) {
7766 case MPI_IOCLOGINFO_FC_INIT_BASE:
7767 desc = "FCP Initiator";
7768 break;
7769 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7770 desc = "FCP Target";
7771 break;
7772 case MPI_IOCLOGINFO_FC_LAN_BASE:
7773 desc = "LAN";
7774 break;
7775 case MPI_IOCLOGINFO_FC_MSG_BASE:
7776 desc = "MPI Message Layer";
7777 break;
7778 case MPI_IOCLOGINFO_FC_LINK_BASE:
7779 desc = "FC Link";
7780 break;
7781 case MPI_IOCLOGINFO_FC_CTX_BASE:
7782 desc = "Context Manager";
7783 break;
7784 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7785 desc = "Invalid Field Offset";
7786 break;
7787 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7788 desc = "State Change Info";
7789 break;
7790 }
7791
7792 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7793 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007794}
7795
7796/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007797/**
Moore, Eric335a9412006-01-17 17:06:23 -07007798 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007799 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007800 * @log_info: U32 LogInfo word from the IOC
7801 *
7802 * Refer to lsi/sp_log.h.
7803 */
7804static void
Moore, Eric335a9412006-01-17 17:06:23 -07007805mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007806{
7807 u32 info = log_info & 0x00FF0000;
7808 char *desc = "unknown";
7809
7810 switch (info) {
7811 case 0x00010000:
7812 desc = "bug! MID not found";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007813 break;
7814
7815 case 0x00020000:
7816 desc = "Parity Error";
7817 break;
7818
7819 case 0x00030000:
7820 desc = "ASYNC Outbound Overrun";
7821 break;
7822
7823 case 0x00040000:
7824 desc = "SYNC Offset Error";
7825 break;
7826
7827 case 0x00050000:
7828 desc = "BM Change";
7829 break;
7830
7831 case 0x00060000:
7832 desc = "Msg In Overflow";
7833 break;
7834
7835 case 0x00070000:
7836 desc = "DMA Error";
7837 break;
7838
7839 case 0x00080000:
7840 desc = "Outbound DMA Overrun";
7841 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007842
Linus Torvalds1da177e2005-04-16 15:20:36 -07007843 case 0x00090000:
7844 desc = "Task Management";
7845 break;
7846
7847 case 0x000A0000:
7848 desc = "Device Problem";
7849 break;
7850
7851 case 0x000B0000:
7852 desc = "Invalid Phase Change";
7853 break;
7854
7855 case 0x000C0000:
7856 desc = "Untagged Table Size";
7857 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007858
Linus Torvalds1da177e2005-04-16 15:20:36 -07007859 }
7860
7861 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7862}
7863
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007864/* strings for sas loginfo */
7865 static char *originator_str[] = {
7866 "IOP", /* 00h */
7867 "PL", /* 01h */
7868 "IR" /* 02h */
7869 };
7870 static char *iop_code_str[] = {
7871 NULL, /* 00h */
7872 "Invalid SAS Address", /* 01h */
7873 NULL, /* 02h */
7874 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007875 "Diag Message Error", /* 04h */
7876 "Task Terminated", /* 05h */
7877 "Enclosure Management", /* 06h */
7878 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007879 };
7880 static char *pl_code_str[] = {
7881 NULL, /* 00h */
7882 "Open Failure", /* 01h */
7883 "Invalid Scatter Gather List", /* 02h */
7884 "Wrong Relative Offset or Frame Length", /* 03h */
7885 "Frame Transfer Error", /* 04h */
7886 "Transmit Frame Connected Low", /* 05h */
7887 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7888 "SATA Read Log Receive Data Error", /* 07h */
7889 "SATA NCQ Fail All Commands After Error", /* 08h */
7890 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7891 "Receive Frame Invalid Message", /* 0Ah */
7892 "Receive Context Message Valid Error", /* 0Bh */
7893 "Receive Frame Current Frame Error", /* 0Ch */
7894 "SATA Link Down", /* 0Dh */
7895 "Discovery SATA Init W IOS", /* 0Eh */
7896 "Config Invalid Page", /* 0Fh */
7897 "Discovery SATA Init Timeout", /* 10h */
7898 "Reset", /* 11h */
7899 "Abort", /* 12h */
7900 "IO Not Yet Executed", /* 13h */
7901 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007902 "Persistent Reservation Out Not Affiliation "
7903 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007904 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007905 "IO Device Missing Delay Retry", /* 17h */
Lucas De Marchi25985ed2011-03-30 22:57:33 -03007906 "IO Cancelled Due to Receive Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007907 NULL, /* 19h */
7908 NULL, /* 1Ah */
7909 NULL, /* 1Bh */
7910 NULL, /* 1Ch */
7911 NULL, /* 1Dh */
7912 NULL, /* 1Eh */
7913 NULL, /* 1Fh */
7914 "Enclosure Management" /* 20h */
7915 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007916 static char *ir_code_str[] = {
7917 "Raid Action Error", /* 00h */
7918 NULL, /* 00h */
7919 NULL, /* 01h */
7920 NULL, /* 02h */
7921 NULL, /* 03h */
7922 NULL, /* 04h */
7923 NULL, /* 05h */
7924 NULL, /* 06h */
7925 NULL /* 07h */
7926 };
7927 static char *raid_sub_code_str[] = {
7928 NULL, /* 00h */
7929 "Volume Creation Failed: Data Passed too "
7930 "Large", /* 01h */
7931 "Volume Creation Failed: Duplicate Volumes "
7932 "Attempted", /* 02h */
7933 "Volume Creation Failed: Max Number "
7934 "Supported Volumes Exceeded", /* 03h */
7935 "Volume Creation Failed: DMA Error", /* 04h */
7936 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7937 "Volume Creation Failed: Error Reading "
7938 "MFG Page 4", /* 06h */
7939 "Volume Creation Failed: Creating Internal "
7940 "Structures", /* 07h */
7941 NULL, /* 08h */
7942 NULL, /* 09h */
7943 NULL, /* 0Ah */
7944 NULL, /* 0Bh */
7945 NULL, /* 0Ch */
7946 NULL, /* 0Dh */
7947 NULL, /* 0Eh */
7948 NULL, /* 0Fh */
7949 "Activation failed: Already Active Volume", /* 10h */
7950 "Activation failed: Unsupported Volume Type", /* 11h */
7951 "Activation failed: Too Many Active Volumes", /* 12h */
7952 "Activation failed: Volume ID in Use", /* 13h */
7953 "Activation failed: Reported Failure", /* 14h */
7954 "Activation failed: Importing a Volume", /* 15h */
7955 NULL, /* 16h */
7956 NULL, /* 17h */
7957 NULL, /* 18h */
7958 NULL, /* 19h */
7959 NULL, /* 1Ah */
7960 NULL, /* 1Bh */
7961 NULL, /* 1Ch */
7962 NULL, /* 1Dh */
7963 NULL, /* 1Eh */
7964 NULL, /* 1Fh */
7965 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7966 "Phys Disk failed: Data Passed too Large", /* 21h */
7967 "Phys Disk failed: DMA Error", /* 22h */
7968 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7969 "Phys Disk failed: Creating Phys Disk Config "
7970 "Page", /* 24h */
7971 NULL, /* 25h */
7972 NULL, /* 26h */
7973 NULL, /* 27h */
7974 NULL, /* 28h */
7975 NULL, /* 29h */
7976 NULL, /* 2Ah */
7977 NULL, /* 2Bh */
7978 NULL, /* 2Ch */
7979 NULL, /* 2Dh */
7980 NULL, /* 2Eh */
7981 NULL, /* 2Fh */
7982 "Compatibility Error: IR Disabled", /* 30h */
Uwe Kleine-Königb5950762010-11-01 15:38:34 -04007983 "Compatibility Error: Inquiry Command Failed", /* 31h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007984 "Compatibility Error: Device not Direct Access "
7985 "Device ", /* 32h */
7986 "Compatibility Error: Removable Device Found", /* 33h */
7987 "Compatibility Error: Device SCSI Version not "
7988 "2 or Higher", /* 34h */
7989 "Compatibility Error: SATA Device, 48 BIT LBA "
7990 "not Supported", /* 35h */
7991 "Compatibility Error: Device doesn't have "
7992 "512 Byte Block Sizes", /* 36h */
7993 "Compatibility Error: Volume Type Check Failed", /* 37h */
7994 "Compatibility Error: Volume Type is "
7995 "Unsupported by FW", /* 38h */
7996 "Compatibility Error: Disk Drive too Small for "
7997 "use in Volume", /* 39h */
7998 "Compatibility Error: Phys Disk for Create "
7999 "Volume not Found", /* 3Ah */
8000 "Compatibility Error: Too Many or too Few "
8001 "Disks for Volume Type", /* 3Bh */
8002 "Compatibility Error: Disk stripe Sizes "
8003 "Must be 64KB", /* 3Ch */
8004 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
8005 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008006
8007/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008008/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008009 * mpt_sas_log_info - Log information returned from SAS IOC.
8010 * @ioc: Pointer to MPT_ADAPTER structure
8011 * @log_info: U32 LogInfo reply word from the IOC
Randy Dunlapfc58fb12010-08-14 13:05:57 -07008012 * @cb_idx: callback function's handle
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008013 *
8014 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008015 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008016static void
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308017mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info, u8 cb_idx)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008018{
8019union loginfo_type {
8020 u32 loginfo;
8021 struct {
8022 u32 subcode:16;
8023 u32 code:8;
8024 u32 originator:4;
8025 u32 bus_type:4;
8026 }dw;
8027};
8028 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07008029 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008030 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07008031 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008032
8033 sas_loginfo.loginfo = log_info;
8034 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008035 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008036 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07008037
8038 originator_desc = originator_str[sas_loginfo.dw.originator];
8039
8040 switch (sas_loginfo.dw.originator) {
8041
8042 case 0: /* IOP */
8043 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008044 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008045 code_desc = iop_code_str[sas_loginfo.dw.code];
8046 break;
8047 case 1: /* PL */
8048 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008049 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008050 code_desc = pl_code_str[sas_loginfo.dw.code];
8051 break;
8052 case 2: /* IR */
8053 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008054 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008055 break;
8056 code_desc = ir_code_str[sas_loginfo.dw.code];
8057 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008058 ARRAY_SIZE(raid_sub_code_str))
Julia Lawall081f4f42010-08-05 22:27:14 +02008059 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07008060 if (sas_loginfo.dw.code == 0)
8061 sub_code_desc =
8062 raid_sub_code_str[sas_loginfo.dw.subcode];
8063 break;
8064 default:
8065 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008066 }
8067
Eric Moorec6c727a2007-01-29 09:44:54 -07008068 if (sub_code_desc != NULL)
8069 printk(MYIOC_s_INFO_FMT
8070 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308071 " SubCode={%s} cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008072 ioc->name, log_info, originator_desc, code_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308073 sub_code_desc, MptCallbacksName[cb_idx]);
Eric Moorec6c727a2007-01-29 09:44:54 -07008074 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008075 printk(MYIOC_s_INFO_FMT
8076 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308077 " SubCode(0x%04x) cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008078 ioc->name, log_info, originator_desc, code_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308079 sas_loginfo.dw.subcode, MptCallbacksName[cb_idx]);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008080 else
8081 printk(MYIOC_s_INFO_FMT
8082 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308083 " SubCode(0x%04x) cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008084 ioc->name, log_info, originator_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308085 sas_loginfo.dw.code, sas_loginfo.dw.subcode,
8086 MptCallbacksName[cb_idx]);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008087}
8088
Linus Torvalds1da177e2005-04-16 15:20:36 -07008089/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008090/**
Eric Moorec6c727a2007-01-29 09:44:54 -07008091 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
8092 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08008093 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07008094 * @mf: Pointer to MPT request frame
8095 *
8096 * Refer to lsi/mpi.h.
8097 **/
8098static void
8099mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
8100{
8101 Config_t *pReq = (Config_t *)mf;
8102 char extend_desc[EVENT_DESCR_STR_SZ];
8103 char *desc = NULL;
8104 u32 form;
8105 u8 page_type;
8106
8107 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
8108 page_type = pReq->ExtPageType;
8109 else
8110 page_type = pReq->Header.PageType;
8111
8112 /*
8113 * ignore invalid page messages for GET_NEXT_HANDLE
8114 */
8115 form = le32_to_cpu(pReq->PageAddress);
8116 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
8117 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
8118 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
8119 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
8120 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
8121 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
8122 return;
8123 }
8124 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
8125 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
8126 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
8127 return;
8128 }
8129
8130 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
8131 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
8132 page_type, pReq->Header.PageNumber, pReq->Action, form);
8133
8134 switch (ioc_status) {
8135
8136 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8137 desc = "Config Page Invalid Action";
8138 break;
8139
8140 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8141 desc = "Config Page Invalid Type";
8142 break;
8143
8144 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8145 desc = "Config Page Invalid Page";
8146 break;
8147
8148 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8149 desc = "Config Page Invalid Data";
8150 break;
8151
8152 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8153 desc = "Config Page No Defaults";
8154 break;
8155
8156 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
8157 desc = "Config Page Can't Commit";
8158 break;
8159 }
8160
8161 if (!desc)
8162 return;
8163
Eric Moore29dd3602007-09-14 18:46:51 -06008164 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
8165 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07008166}
8167
8168/**
8169 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07008170 * @ioc: Pointer to MPT_ADAPTER structure
8171 * @ioc_status: U32 IOCStatus word from IOC
8172 * @mf: Pointer to MPT request frame
8173 *
8174 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008175 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07008176static void
Eric Moorec6c727a2007-01-29 09:44:54 -07008177mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008178{
8179 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06008180 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008181
8182 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07008183
8184/****************************************************************************/
8185/* Common IOCStatus values for all replies */
8186/****************************************************************************/
8187
Linus Torvalds1da177e2005-04-16 15:20:36 -07008188 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
8189 desc = "Invalid Function";
8190 break;
8191
8192 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
8193 desc = "Busy";
8194 break;
8195
8196 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
8197 desc = "Invalid SGL";
8198 break;
8199
8200 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
8201 desc = "Internal Error";
8202 break;
8203
8204 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
8205 desc = "Reserved";
8206 break;
8207
8208 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
8209 desc = "Insufficient Resources";
8210 break;
8211
8212 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
8213 desc = "Invalid Field";
8214 break;
8215
8216 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
8217 desc = "Invalid State";
8218 break;
8219
Eric Moorec6c727a2007-01-29 09:44:54 -07008220/****************************************************************************/
8221/* Config IOCStatus values */
8222/****************************************************************************/
8223
Linus Torvalds1da177e2005-04-16 15:20:36 -07008224 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8225 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8226 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8227 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8228 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8229 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008230 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008231 break;
8232
Eric Moorec6c727a2007-01-29 09:44:54 -07008233/****************************************************************************/
8234/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
8235/* */
8236/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
8237/* */
8238/****************************************************************************/
8239
Linus Torvalds1da177e2005-04-16 15:20:36 -07008240 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008241 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008242 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
8243 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
8244 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
8245 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008246 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008247 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008248 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008249 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008250 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008251 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07008252 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008253 break;
8254
Eric Moorec6c727a2007-01-29 09:44:54 -07008255/****************************************************************************/
8256/* SCSI Target values */
8257/****************************************************************************/
8258
8259 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
8260 desc = "Target: Priority IO";
8261 break;
8262
8263 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
8264 desc = "Target: Invalid Port";
8265 break;
8266
8267 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
8268 desc = "Target Invalid IO Index:";
8269 break;
8270
8271 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
8272 desc = "Target: Aborted";
8273 break;
8274
8275 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
8276 desc = "Target: No Conn Retryable";
8277 break;
8278
8279 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
8280 desc = "Target: No Connection";
8281 break;
8282
8283 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
8284 desc = "Target: Transfer Count Mismatch";
8285 break;
8286
8287 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
8288 desc = "Target: STS Data not Sent";
8289 break;
8290
8291 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
8292 desc = "Target: Data Offset Error";
8293 break;
8294
8295 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
8296 desc = "Target: Too Much Write Data";
8297 break;
8298
8299 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
8300 desc = "Target: IU Too Short";
8301 break;
8302
8303 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
8304 desc = "Target: ACK NAK Timeout";
8305 break;
8306
8307 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
8308 desc = "Target: Nak Received";
8309 break;
8310
8311/****************************************************************************/
8312/* Fibre Channel Direct Access values */
8313/****************************************************************************/
8314
8315 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
8316 desc = "FC: Aborted";
8317 break;
8318
8319 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
8320 desc = "FC: RX ID Invalid";
8321 break;
8322
8323 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
8324 desc = "FC: DID Invalid";
8325 break;
8326
8327 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
8328 desc = "FC: Node Logged Out";
8329 break;
8330
8331 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
8332 desc = "FC: Exchange Canceled";
8333 break;
8334
8335/****************************************************************************/
8336/* LAN values */
8337/****************************************************************************/
8338
8339 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
8340 desc = "LAN: Device not Found";
8341 break;
8342
8343 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
8344 desc = "LAN: Device Failure";
8345 break;
8346
8347 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
8348 desc = "LAN: Transmit Error";
8349 break;
8350
8351 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
8352 desc = "LAN: Transmit Aborted";
8353 break;
8354
8355 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
8356 desc = "LAN: Receive Error";
8357 break;
8358
8359 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
8360 desc = "LAN: Receive Aborted";
8361 break;
8362
8363 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
8364 desc = "LAN: Partial Packet";
8365 break;
8366
8367 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
8368 desc = "LAN: Canceled";
8369 break;
8370
8371/****************************************************************************/
8372/* Serial Attached SCSI values */
8373/****************************************************************************/
8374
8375 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
8376 desc = "SAS: SMP Request Failed";
8377 break;
8378
8379 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
8380 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07008381 break;
8382
8383 default:
8384 desc = "Others";
8385 break;
8386 }
Eric Moorec6c727a2007-01-29 09:44:54 -07008387
8388 if (!desc)
8389 return;
8390
Eric Moore29dd3602007-09-14 18:46:51 -06008391 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
8392 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008393}
8394
8395/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008396EXPORT_SYMBOL(mpt_attach);
8397EXPORT_SYMBOL(mpt_detach);
8398#ifdef CONFIG_PM
8399EXPORT_SYMBOL(mpt_resume);
8400EXPORT_SYMBOL(mpt_suspend);
8401#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07008402EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008403EXPORT_SYMBOL(mpt_register);
8404EXPORT_SYMBOL(mpt_deregister);
8405EXPORT_SYMBOL(mpt_event_register);
8406EXPORT_SYMBOL(mpt_event_deregister);
8407EXPORT_SYMBOL(mpt_reset_register);
8408EXPORT_SYMBOL(mpt_reset_deregister);
8409EXPORT_SYMBOL(mpt_device_driver_register);
8410EXPORT_SYMBOL(mpt_device_driver_deregister);
8411EXPORT_SYMBOL(mpt_get_msg_frame);
8412EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05308413EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008414EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008415EXPORT_SYMBOL(mpt_send_handshake_request);
8416EXPORT_SYMBOL(mpt_verify_adapter);
8417EXPORT_SYMBOL(mpt_GetIocState);
8418EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008419EXPORT_SYMBOL(mpt_HardResetHandler);
8420EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008421EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008422EXPORT_SYMBOL(mpt_alloc_fw_memory);
8423EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02008424EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07008425EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008426
Linus Torvalds1da177e2005-04-16 15:20:36 -07008427/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008428/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008429 * fusion_init - Fusion MPT base driver initialization routine.
8430 *
8431 * Returns 0 for success, non-zero for failure.
8432 */
8433static int __init
8434fusion_init(void)
8435{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308436 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008437
8438 show_mptmod_ver(my_NAME, my_VERSION);
8439 printk(KERN_INFO COPYRIGHT "\n");
8440
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308441 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
8442 MptCallbacks[cb_idx] = NULL;
8443 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
8444 MptEvHandlers[cb_idx] = NULL;
8445 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008446 }
8447
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008448 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07008449 * EventNotification handling.
8450 */
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308451 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER,
8452 "mptbase_reply");
Linus Torvalds1da177e2005-04-16 15:20:36 -07008453
8454 /* Register for hard reset handling callbacks.
8455 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05308456 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008457
8458#ifdef CONFIG_PROC_FS
8459 (void) procmpt_create();
8460#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008461 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008462}
8463
8464/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008465/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008466 * fusion_exit - Perform driver unload cleanup.
8467 *
8468 * This routine frees all resources associated with each MPT adapter
8469 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
8470 */
8471static void __exit
8472fusion_exit(void)
8473{
8474
Linus Torvalds1da177e2005-04-16 15:20:36 -07008475 mpt_reset_deregister(mpt_base_index);
8476
8477#ifdef CONFIG_PROC_FS
8478 procmpt_destroy();
8479#endif
8480}
8481
Linus Torvalds1da177e2005-04-16 15:20:36 -07008482module_init(fusion_init);
8483module_exit(fusion_exit);