blob: 68f57d3bcca1fc665cce2140a51ea5de81fa3874 [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
kashyap.desai@lsi.come62cca12011-08-04 16:42:15 +053066#include <linux/kthread.h>
67#include <scsi/scsi_host.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69#include "mptbase.h"
Eric Moore7c431e52007-06-13 16:34:36 -060070#include "lsi/mpi_log_fc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
72/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
73#define my_NAME "Fusion MPT base driver"
74#define my_VERSION MPT_LINUX_VERSION_COMMON
75#define MYNAM "mptbase"
76
77MODULE_AUTHOR(MODULEAUTHOR);
78MODULE_DESCRIPTION(my_NAME);
79MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070080MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
82/*
83 * cmd line parameters
84 */
Kashyap, Desaie3829682009-01-08 14:27:16 +053085
86static int mpt_msi_enable_spi;
87module_param(mpt_msi_enable_spi, int, 0);
Joe Perches85ee7a12011-04-23 20:38:19 -070088MODULE_PARM_DESC(mpt_msi_enable_spi,
89 " Enable MSI Support for SPI controllers (default=0)");
Kashyap, Desaie3829682009-01-08 14:27:16 +053090
91static int mpt_msi_enable_fc;
92module_param(mpt_msi_enable_fc, int, 0);
Joe Perches85ee7a12011-04-23 20:38:19 -070093MODULE_PARM_DESC(mpt_msi_enable_fc,
94 " Enable MSI Support for FC controllers (default=0)");
Kashyap, Desaie3829682009-01-08 14:27:16 +053095
96static int mpt_msi_enable_sas;
Yinghai Lu5ce78682009-02-18 11:25:32 -080097module_param(mpt_msi_enable_sas, int, 0);
Joe Perches85ee7a12011-04-23 20:38:19 -070098MODULE_PARM_DESC(mpt_msi_enable_sas,
99 " Enable MSI Support for SAS controllers (default=0)");
Christoph Hellwig4ddce142006-01-17 13:44:29 +0000100
Eric Moore793955f2007-01-29 09:42:20 -0700101static int mpt_channel_mapping;
102module_param(mpt_channel_mapping, int, 0);
103MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
104
Prakash, Sathya436ace72007-07-24 15:42:08 +0530105static int mpt_debug_level;
James Bottomleydb47c2d2007-07-28 13:40:21 -0400106static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
107module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
108 &mpt_debug_level, 0600);
Joe Perches85ee7a12011-04-23 20:38:19 -0700109MODULE_PARM_DESC(mpt_debug_level,
110 " debug level - refer to mptdebug.h - (default=0)");
Kashyap, Desaie3829682009-01-08 14:27:16 +0530111
Kashyap, Desai2f4c7822009-01-06 15:03:37 +0530112int mpt_fwfault_debug;
113EXPORT_SYMBOL(mpt_fwfault_debug);
Rusty Russell57ba4712010-08-11 23:04:39 -0600114module_param(mpt_fwfault_debug, int, 0600);
Joe Perches85ee7a12011-04-23 20:38:19 -0700115MODULE_PARM_DESC(mpt_fwfault_debug,
116 "Enable detection of Firmware fault and halt Firmware on fault - (default=0)");
Kashyap, Desai2f4c7822009-01-06 15:03:37 +0530117
Ferenc Wagner8af3d8d2011-08-25 14:44:57 +0200118static char MptCallbacksName[MPT_MAX_PROTOCOL_DRIVERS]
119 [MPT_MAX_CALLBACKNAME_LEN+1];
Prakash, Sathya436ace72007-07-24 15:42:08 +0530120
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121#ifdef MFCNT
122static int mfcounter = 0;
123#define PRINT_MF_COUNT 20000
124#endif
125
126/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
127/*
128 * Public data...
129 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131#define WHOINIT_UNKNOWN 0xAA
132
133/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
134/*
135 * Private data...
136 */
137 /* Adapter link list */
138LIST_HEAD(ioc_list);
139 /* Callback lookup table */
140static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
141 /* Protocol driver class lookup table */
142static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
143 /* Event handler lookup table */
144static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
145 /* Reset handler lookup table */
146static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
147static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
148
Erik Ekmane47c11c2009-12-14 21:21:56 +0100149#ifdef CONFIG_PROC_FS
150static struct proc_dir_entry *mpt_proc_root_dir;
151#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530153/*
154 * Driver Callback Index's
155 */
156static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
157static u8 last_drv_idx;
158
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
160/*
161 * Forward protos...
162 */
David Howells7d12e782006-10-05 14:55:46 +0100163static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530164static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
165 MPT_FRAME_HDR *reply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
167 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
168 int sleepFlag);
169static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
170static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
171static void mpt_adapter_disable(MPT_ADAPTER *ioc);
172static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
173
174static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
175static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
177static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
178static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
179static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
180static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200181static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
183static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
184static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
185static int PrimeIocFifos(MPT_ADAPTER *ioc);
186static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
187static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
188static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
189static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200191int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
193static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
194static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
195static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530196static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Kashyap, Desaifd761752009-05-29 16:39:06 +0530197static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch,
198 int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200200static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
201static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
203#ifdef CONFIG_PROC_FS
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -0700204static const struct file_operations mpt_summary_proc_fops;
205static const struct file_operations mpt_version_proc_fops;
206static const struct file_operations mpt_iocinfo_proc_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207#endif
208static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
209
Kashyap, Desaifd761752009-05-29 16:39:06 +0530210static int ProcessEventNotification(MPT_ADAPTER *ioc,
211 EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700212static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700214static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530215static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info , u8 cb_idx);
Moore, Ericc972c702006-03-14 09:14:06 -0700216static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700217static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
219/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220static int __init fusion_init (void);
221static void __exit fusion_exit (void);
222
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223#define CHIPREG_READ32(addr) readl_relaxed(addr)
224#define CHIPREG_READ32_dmasync(addr) readl(addr)
225#define CHIPREG_WRITE32(addr,val) writel(val, addr)
226#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
227#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
228
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600229static void
230pci_disable_io_access(struct pci_dev *pdev)
231{
232 u16 command_reg;
233
234 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
235 command_reg &= ~1;
236 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
237}
238
239static void
240pci_enable_io_access(struct pci_dev *pdev)
241{
242 u16 command_reg;
243
244 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
245 command_reg |= 1;
246 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
247}
248
James Bottomleydb47c2d2007-07-28 13:40:21 -0400249static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
250{
251 int ret = param_set_int(val, kp);
252 MPT_ADAPTER *ioc;
253
254 if (ret)
255 return ret;
256
257 list_for_each_entry(ioc, &ioc_list, list)
258 ioc->debug_level = mpt_debug_level;
259 return 0;
260}
261
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530262/**
263 * mpt_get_cb_idx - obtain cb_idx for registered driver
264 * @dclass: class driver enum
265 *
266 * Returns cb_idx, or zero means it wasn't found
267 **/
268static u8
269mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
270{
271 u8 cb_idx;
272
273 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
274 if (MptDriverClass[cb_idx] == dclass)
275 return cb_idx;
276 return 0;
277}
278
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530279/**
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530280 * mpt_is_discovery_complete - determine if discovery has completed
281 * @ioc: per adatper instance
282 *
283 * Returns 1 when discovery completed, else zero.
284 */
285static int
286mpt_is_discovery_complete(MPT_ADAPTER *ioc)
287{
288 ConfigExtendedPageHeader_t hdr;
289 CONFIGPARMS cfg;
290 SasIOUnitPage0_t *buffer;
291 dma_addr_t dma_handle;
292 int rc = 0;
293
294 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
295 memset(&cfg, 0, sizeof(CONFIGPARMS));
296 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
297 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
298 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
299 cfg.cfghdr.ehdr = &hdr;
300 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
301
302 if ((mpt_config(ioc, &cfg)))
303 goto out;
304 if (!hdr.ExtPageLength)
305 goto out;
306
307 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
308 &dma_handle);
309 if (!buffer)
310 goto out;
311
312 cfg.physAddr = dma_handle;
313 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
314
315 if ((mpt_config(ioc, &cfg)))
316 goto out_free_consistent;
317
318 if (!(buffer->PhyData[0].PortFlags &
319 MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS))
320 rc = 1;
321
322 out_free_consistent:
323 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
324 buffer, dma_handle);
325 out:
326 return rc;
327}
328
kashyap.desai@lsi.come62cca12011-08-04 16:42:15 +0530329
330/**
331 * mpt_remove_dead_ioc_func - kthread context to remove dead ioc
332 * @arg: input argument, used to derive ioc
333 *
334 * Return 0 if controller is removed from pci subsystem.
335 * Return -1 for other case.
336 */
337static int mpt_remove_dead_ioc_func(void *arg)
338{
339 MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
340 struct pci_dev *pdev;
341
342 if ((ioc == NULL))
343 return -1;
344
345 pdev = ioc->pcidev;
346 if ((pdev == NULL))
347 return -1;
348
Rafael J. Wysocki64cdb412014-01-10 15:27:56 +0100349 pci_stop_and_remove_bus_device_locked(pdev);
kashyap.desai@lsi.come62cca12011-08-04 16:42:15 +0530350 return 0;
351}
352
353
354
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530355/**
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530356 * mpt_fault_reset_work - work performed on workq after ioc fault
357 * @work: input argument, used to derive ioc
358 *
359**/
360static void
361mpt_fault_reset_work(struct work_struct *work)
362{
363 MPT_ADAPTER *ioc =
364 container_of(work, MPT_ADAPTER, fault_reset_work.work);
365 u32 ioc_raw_state;
366 int rc;
367 unsigned long flags;
kashyap.desai@lsi.come62cca12011-08-04 16:42:15 +0530368 MPT_SCSI_HOST *hd;
369 struct task_struct *p;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530370
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530371 if (ioc->ioc_reset_in_progress || !ioc->active)
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530372 goto out;
373
kashyap.desai@lsi.come62cca12011-08-04 16:42:15 +0530374
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530375 ioc_raw_state = mpt_GetIocState(ioc, 0);
kashyap.desai@lsi.come62cca12011-08-04 16:42:15 +0530376 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_MASK) {
377 printk(MYIOC_s_INFO_FMT "%s: IOC is non-operational !!!!\n",
378 ioc->name, __func__);
379
380 /*
381 * Call mptscsih_flush_pending_cmds callback so that we
382 * flush all pending commands back to OS.
383 * This call is required to aovid deadlock at block layer.
384 * Dead IOC will fail to do diag reset,and this call is safe
385 * since dead ioc will never return any command back from HW.
386 */
387 hd = shost_priv(ioc->sh);
388 ioc->schedule_dead_ioc_flush_running_cmds(hd);
389
390 /*Remove the Dead Host */
391 p = kthread_run(mpt_remove_dead_ioc_func, ioc,
392 "mpt_dead_ioc_%d", ioc->id);
393 if (IS_ERR(p)) {
394 printk(MYIOC_s_ERR_FMT
395 "%s: Running mpt_dead_ioc thread failed !\n",
396 ioc->name, __func__);
397 } else {
398 printk(MYIOC_s_WARN_FMT
399 "%s: Running mpt_dead_ioc thread success !\n",
400 ioc->name, __func__);
401 }
402 return; /* don't rearm timer */
403 }
404
405 if ((ioc_raw_state & MPI_IOC_STATE_MASK)
406 == MPI_IOC_STATE_FAULT) {
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530407 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700408 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530409 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700410 ioc->name, __func__);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530411 rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
412 printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700413 __func__, (rc == 0) ? "success" : "failed");
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530414 ioc_raw_state = mpt_GetIocState(ioc, 0);
415 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
416 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
417 "reset (%04xh)\n", ioc->name, ioc_raw_state &
418 MPI_DOORBELL_DATA_MASK);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530419 } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) {
420 if ((mpt_is_discovery_complete(ioc))) {
421 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing "
422 "discovery_quiesce_io flag\n", ioc->name));
423 ioc->sas_discovery_quiesce_io = 0;
424 }
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530425 }
426
427 out:
428 /*
429 * Take turns polling alternate controller
430 */
431 if (ioc->alt_ioc)
432 ioc = ioc->alt_ioc;
433
434 /* rearm the timer */
Kashyap, Desai2f187862009-05-29 16:52:37 +0530435 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530436 if (ioc->reset_work_q)
437 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
438 msecs_to_jiffies(MPT_POLLING_INTERVAL));
Kashyap, Desai2f187862009-05-29 16:52:37 +0530439 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530440}
441
442
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600443/*
444 * Process turbo (context) reply...
445 */
446static void
447mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
448{
449 MPT_FRAME_HDR *mf = NULL;
450 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530451 u16 req_idx = 0;
452 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600453
Prakash, Sathya436ace72007-07-24 15:42:08 +0530454 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600455 ioc->name, pa));
456
457 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
458 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
459 req_idx = pa & 0x0000FFFF;
460 cb_idx = (pa & 0x00FF0000) >> 16;
461 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
462 break;
463 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530464 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600465 /*
466 * Blind set of mf to NULL here was fatal
467 * after lan_reply says "freeme"
468 * Fix sort of combined with an optimization here;
469 * added explicit check for case where lan_reply
470 * was just returning 1 and doing nothing else.
471 * For this case skip the callback, but set up
472 * proper mf value first here:-)
473 */
474 if ((pa & 0x58000000) == 0x58000000) {
475 req_idx = pa & 0x0000FFFF;
476 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
477 mpt_free_msg_frame(ioc, mf);
478 mb();
479 return;
480 break;
481 }
482 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
483 break;
484 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530485 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600486 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
487 break;
488 default:
489 cb_idx = 0;
490 BUG();
491 }
492
493 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530494 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600495 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600496 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700497 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600498 goto out;
499 }
500
501 if (MptCallbacks[cb_idx](ioc, mf, mr))
502 mpt_free_msg_frame(ioc, mf);
503 out:
504 mb();
505}
506
507static void
508mpt_reply(MPT_ADAPTER *ioc, u32 pa)
509{
510 MPT_FRAME_HDR *mf;
511 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530512 u16 req_idx;
513 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600514 int freeme;
515
516 u32 reply_dma_low;
517 u16 ioc_stat;
518
519 /* non-TURBO reply! Hmmm, something may be up...
520 * Newest turbo reply mechanism; get address
521 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
522 */
523
524 /* Map DMA address of reply header to cpu address.
525 * pa is 32 bits - but the dma address may be 32 or 64 bits
526 * get offset based only only the low addresses
527 */
528
529 reply_dma_low = (pa <<= 1);
530 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
531 (reply_dma_low - ioc->reply_frames_low_dma));
532
533 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
534 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
535 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
536
Prakash, Sathya436ace72007-07-24 15:42:08 +0530537 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 -0600538 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600539 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600540
541 /* Check/log IOC log info
542 */
543 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
544 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
545 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
546 if (ioc->bus_type == FC)
547 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700548 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700549 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600550 else if (ioc->bus_type == SAS)
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530551 mpt_sas_log_info(ioc, log_info, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600552 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600553
Eric Moorec6c727a2007-01-29 09:44:54 -0700554 if (ioc_stat & MPI_IOCSTATUS_MASK)
555 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600556
557 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530558 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600559 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600560 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700561 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600562 freeme = 0;
563 goto out;
564 }
565
566 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
567
568 out:
569 /* Flush (non-TURBO) reply with a WRITE! */
570 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
571
572 if (freeme)
573 mpt_free_msg_frame(ioc, mf);
574 mb();
575}
576
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800578/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
580 * @irq: irq number (not used)
581 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 *
583 * This routine is registered via the request_irq() kernel API call,
584 * and handles all interrupts generated from a specific MPT adapter
585 * (also referred to as a IO Controller or IOC).
586 * This routine must clear the interrupt from the adapter and does
587 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200588 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 *
590 * This routine handles register-level access of the adapter but
591 * dispatches (calls) a protocol-specific callback routine to handle
592 * the protocol-specific details of the MPT request completion.
593 */
594static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100595mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600597 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600598 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
599
600 if (pa == 0xFFFFFFFF)
601 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
603 /*
604 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600606 do {
607 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600608 mpt_reply(ioc, pa);
609 else
610 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600611 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
612 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
614 return IRQ_HANDLED;
615}
616
617/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800618/**
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530619 * mptbase_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 * @ioc: Pointer to MPT_ADAPTER structure
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530621 * @req: Pointer to original MPT request frame
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
623 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800624 * MPT base driver's callback routine; all base driver
625 * "internal" request/reply processing is routed here.
626 * Currently used for EventNotification and EventAck handling.
627 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200628 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 * should be freed, or 0 if it shouldn't.
630 */
631static int
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530632mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530634 EventNotificationReply_t *pEventReply;
635 u8 event;
636 int evHandlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 int freereq = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530639 switch (reply->u.hdr.Function) {
640 case MPI_FUNCTION_EVENT_NOTIFICATION:
641 pEventReply = (EventNotificationReply_t *)reply;
642 evHandlers = 0;
643 ProcessEventNotification(ioc, pEventReply, &evHandlers);
644 event = le32_to_cpu(pEventReply->Event) & 0xFF;
645 if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 freereq = 0;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530647 if (event != MPI_EVENT_EVENT_CHANGE)
648 break;
649 case MPI_FUNCTION_CONFIG:
650 case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
651 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Joe Lawrence9f213162014-06-25 17:06:54 -0400652 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
653 memcpy(ioc->mptbase_cmds.reply, reply,
654 min(MPT_DEFAULT_FRAME_SIZE,
655 4 * reply->u.reply.MsgLength));
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530656 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
657 ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
658 complete(&ioc->mptbase_cmds.done);
659 } else
660 freereq = 0;
661 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF)
662 freereq = 1;
663 break;
664 case MPI_FUNCTION_EVENT_ACK:
665 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
666 "EventAck reply received\n", ioc->name));
667 break;
668 default:
669 printk(MYIOC_s_ERR_FMT
670 "Unexpected msg function (=%02Xh) reply received!\n",
671 ioc->name, reply->u.hdr.Function);
672 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 }
674
675 /*
676 * Conditionally tell caller to free the original
677 * EventNotification/EventAck/unexpected request frame!
678 */
679 return freereq;
680}
681
682/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
683/**
684 * mpt_register - Register protocol-specific main callback handler.
685 * @cbfunc: callback function pointer
686 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
Randy Dunlapfc58fb12010-08-14 13:05:57 -0700687 * @func_name: call function's name
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 *
689 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800690 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 * protocol-specific driver must do this before it will be able to
692 * use any IOC resources, such as obtaining request frames.
693 *
694 * NOTES: The SCSI protocol driver currently calls this routine thrice
695 * in order to register separate callbacks; one for "normal" SCSI IO;
696 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
697 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530698 * Returns u8 valued "handle" in the range (and S.O.D. order)
699 * {N,...,7,6,5,...,1} if successful.
700 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
701 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530703u8
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530704mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass, char *func_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530706 u8 cb_idx;
707 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
709 /*
710 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
711 * (slot/handle 0 is reserved!)
712 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530713 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
714 if (MptCallbacks[cb_idx] == NULL) {
715 MptCallbacks[cb_idx] = cbfunc;
716 MptDriverClass[cb_idx] = dclass;
717 MptEvHandlers[cb_idx] = NULL;
718 last_drv_idx = cb_idx;
Ferenc Wagner8af3d8d2011-08-25 14:44:57 +0200719 strlcpy(MptCallbacksName[cb_idx], func_name,
720 MPT_MAX_CALLBACKNAME_LEN+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 break;
722 }
723 }
724
725 return last_drv_idx;
726}
727
728/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
729/**
730 * mpt_deregister - Deregister a protocol drivers resources.
731 * @cb_idx: previously registered callback handle
732 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800733 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 * module is unloaded.
735 */
736void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530737mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600739 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 MptCallbacks[cb_idx] = NULL;
741 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
742 MptEvHandlers[cb_idx] = NULL;
743
744 last_drv_idx++;
745 }
746}
747
748/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
749/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800750 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 * @cb_idx: previously registered (via mpt_register) callback handle
752 * @ev_cbfunc: callback function
753 *
754 * This routine can be called by one or more protocol-specific drivers
755 * if/when they choose to be notified of MPT events.
756 *
757 * Returns 0 for success.
758 */
759int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530760mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600762 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 return -1;
764
765 MptEvHandlers[cb_idx] = ev_cbfunc;
766 return 0;
767}
768
769/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
770/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800771 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 * @cb_idx: previously registered callback handle
773 *
774 * Each protocol-specific driver should call this routine
775 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800776 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 */
778void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530779mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600781 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 return;
783
784 MptEvHandlers[cb_idx] = NULL;
785}
786
787/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
788/**
789 * mpt_reset_register - Register protocol-specific IOC reset handler.
790 * @cb_idx: previously registered (via mpt_register) callback handle
791 * @reset_func: reset function
792 *
793 * This routine can be called by one or more protocol-specific drivers
794 * if/when they choose to be notified of IOC resets.
795 *
796 * Returns 0 for success.
797 */
798int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530799mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530801 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 return -1;
803
804 MptResetHandlers[cb_idx] = reset_func;
805 return 0;
806}
807
808/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
809/**
810 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
811 * @cb_idx: previously registered callback handle
812 *
813 * Each protocol-specific driver should call this routine
814 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800815 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 */
817void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530818mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530820 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 return;
822
823 MptResetHandlers[cb_idx] = NULL;
824}
825
826/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
827/**
828 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800829 * @dd_cbfunc: driver callbacks struct
830 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 */
832int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530833mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834{
835 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600836 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
Eric Moore8d6d83e2007-09-14 18:47:40 -0600838 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400839 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
841 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
842
843 /* call per pci device probe entry point */
844 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600845 id = ioc->pcidev->driver ?
846 ioc->pcidev->driver->id_table : NULL;
847 if (dd_cbfunc->probe)
848 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 }
850
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400851 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852}
853
854/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
855/**
856 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800857 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 */
859void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530860mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861{
862 struct mpt_pci_driver *dd_cbfunc;
863 MPT_ADAPTER *ioc;
864
Eric Moore8d6d83e2007-09-14 18:47:40 -0600865 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 return;
867
868 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
869
870 list_for_each_entry(ioc, &ioc_list, list) {
871 if (dd_cbfunc->remove)
872 dd_cbfunc->remove(ioc->pcidev);
873 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200874
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 MptDeviceDriverHandlers[cb_idx] = NULL;
876}
877
878
879/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
880/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800881 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530882 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 * @ioc: Pointer to MPT adapter structure
884 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800885 * Obtain an MPT request frame from the pool (of 1024) that are
886 * allocated per MPT adapter.
887 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 * Returns pointer to a MPT request frame or %NULL if none are available
889 * or IOC is not active.
890 */
891MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530892mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893{
894 MPT_FRAME_HDR *mf;
895 unsigned long flags;
896 u16 req_idx; /* Request index */
897
898 /* validate handle and ioc identifier */
899
900#ifdef MFCNT
901 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600902 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
903 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904#endif
905
906 /* If interrupts are not attached, do not return a request frame */
907 if (!ioc->active)
908 return NULL;
909
910 spin_lock_irqsave(&ioc->FreeQlock, flags);
911 if (!list_empty(&ioc->FreeQ)) {
912 int req_offset;
913
914 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
915 u.frame.linkage.list);
916 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200917 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530918 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
920 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500921 req_idx = req_offset / ioc->req_sz;
922 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600924 /* Default, will be changed if necessary in SG generation */
925 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926#ifdef MFCNT
927 ioc->mfcnt++;
928#endif
929 }
930 else
931 mf = NULL;
932 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
933
934#ifdef MFCNT
935 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600936 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
937 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
938 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 mfcounter++;
940 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600941 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
942 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943#endif
944
Eric Moore29dd3602007-09-14 18:46:51 -0600945 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
946 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 return mf;
948}
949
950/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
951/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800952 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530953 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 * @ioc: Pointer to MPT adapter structure
955 * @mf: Pointer to MPT request frame
956 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800957 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 * specific MPT adapter.
959 */
960void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530961mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962{
963 u32 mf_dma_addr;
964 int req_offset;
965 u16 req_idx; /* Request index */
966
967 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530968 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
970 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500971 req_idx = req_offset / ioc->req_sz;
972 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
974
Prakash, Sathya436ace72007-07-24 15:42:08 +0530975 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200977 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600978 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
979 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
980 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
982}
983
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530984/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800985 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530986 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530987 * @ioc: Pointer to MPT adapter structure
988 * @mf: Pointer to MPT request frame
989 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800990 * Send a protocol-specific MPT request frame to an IOC using
991 * hi-priority request queue.
992 *
993 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530994 * specific MPT adapter.
995 **/
996void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530997mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530998{
999 u32 mf_dma_addr;
1000 int req_offset;
1001 u16 req_idx; /* Request index */
1002
1003 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301004 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301005 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
1006 req_idx = req_offset / ioc->req_sz;
1007 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
1008 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
1009
1010 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
1011
1012 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
1013 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
1014 ioc->name, mf_dma_addr, req_idx));
1015 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
1016}
1017
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1019/**
1020 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 * @ioc: Pointer to MPT adapter structure
1022 * @mf: Pointer to MPT request frame
1023 *
1024 * This routine places a MPT request frame back on the MPT adapter's
1025 * FreeQ.
1026 */
1027void
1028mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
1029{
1030 unsigned long flags;
1031
1032 /* Put Request back on FreeQ! */
1033 spin_lock_irqsave(&ioc->FreeQlock, flags);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301034 if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf)
1035 goto out;
1036 /* signature to know if this mf is freed */
1037 mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf);
Matthew Wilcoxecc3bc92014-03-27 16:40:35 -04001038 list_add(&mf->u.frame.linkage.list, &ioc->FreeQ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039#ifdef MFCNT
1040 ioc->mfcnt--;
1041#endif
Kashyap, Desai2f187862009-05-29 16:52:37 +05301042 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1044}
1045
1046/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1047/**
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301048 * mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 * @pAddr: virtual address for SGE
1050 * @flagslength: SGE flags and data transfer length
1051 * @dma_addr: Physical address
1052 *
1053 * This routine places a MPT request frame back on the MPT adapter's
1054 * FreeQ.
1055 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301056static void
1057mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058{
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301059 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
1060 pSge->FlagsLength = cpu_to_le32(flagslength);
1061 pSge->Address = cpu_to_le32(dma_addr);
1062}
1063
1064/**
1065 * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
1066 * @pAddr: virtual address for SGE
1067 * @flagslength: SGE flags and data transfer length
1068 * @dma_addr: Physical address
1069 *
1070 * This routine places a MPT request frame back on the MPT adapter's
1071 * FreeQ.
1072 **/
1073static void
1074mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1075{
1076 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1077 pSge->Address.Low = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301078 (lower_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301079 pSge->Address.High = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301080 (upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301081 pSge->FlagsLength = cpu_to_le32
1082 ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1083}
1084
1085/**
Randy Dunlap9cf46a32009-06-13 19:37:18 -07001086 * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr (1078 workaround).
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301087 * @pAddr: virtual address for SGE
1088 * @flagslength: SGE flags and data transfer length
1089 * @dma_addr: Physical address
1090 *
1091 * This routine places a MPT request frame back on the MPT adapter's
1092 * FreeQ.
1093 **/
1094static void
1095mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1096{
1097 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1098 u32 tmp;
1099
1100 pSge->Address.Low = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301101 (lower_32_bits(dma_addr));
1102 tmp = (u32)(upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301103
1104 /*
1105 * 1078 errata workaround for the 36GB limitation
1106 */
1107 if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {
1108 flagslength |=
1109 MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
1110 tmp |= (1<<31);
1111 if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
1112 printk(KERN_DEBUG "1078 P0M2 addressing for "
1113 "addr = 0x%llx len = %d\n",
1114 (unsigned long long)dma_addr,
1115 MPI_SGE_LENGTH(flagslength));
1116 }
1117
1118 pSge->Address.High = cpu_to_le32(tmp);
1119 pSge->FlagsLength = cpu_to_le32(
1120 (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1121}
1122
1123/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1124/**
1125 * mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
1126 * @pAddr: virtual address for SGE
1127 * @next: nextChainOffset value (u32's)
1128 * @length: length of next SGL segment
1129 * @dma_addr: Physical address
1130 *
1131 */
1132static void
1133mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1134{
1135 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
1136 pChain->Length = cpu_to_le16(length);
1137 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
1138 pChain->NextChainOffset = next;
1139 pChain->Address = cpu_to_le32(dma_addr);
1140}
1141
1142/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1143/**
1144 * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
1145 * @pAddr: virtual address for SGE
1146 * @next: nextChainOffset value (u32's)
1147 * @length: length of next SGL segment
1148 * @dma_addr: Physical address
1149 *
1150 */
1151static void
1152mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1153{
1154 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 u32 tmp = dma_addr & 0xFFFFFFFF;
1156
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301157 pChain->Length = cpu_to_le16(length);
1158 pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
1159 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301161 pChain->NextChainOffset = next;
1162
1163 pChain->Address.Low = cpu_to_le32(tmp);
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301164 tmp = (u32)(upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301165 pChain->Address.High = cpu_to_le32(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166}
1167
1168/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1169/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001170 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301171 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 * @ioc: Pointer to MPT adapter structure
1173 * @reqBytes: Size of the request in bytes
1174 * @req: Pointer to MPT request frame
1175 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1176 *
1177 * This routine is used exclusively to send MptScsiTaskMgmt
1178 * requests since they are required to be sent via doorbell handshake.
1179 *
1180 * NOTE: It is the callers responsibility to byte-swap fields in the
1181 * request which are greater than 1 byte in size.
1182 *
1183 * Returns 0 for success, non-zero for failure.
1184 */
1185int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301186mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187{
Eric Moorecd2c6192007-01-29 09:47:47 -07001188 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 u8 *req_as_bytes;
1190 int ii;
1191
1192 /* State is known to be good upon entering
1193 * this function so issue the bus reset
1194 * request.
1195 */
1196
1197 /*
1198 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1199 * setting cb_idx/req_idx. But ONLY if this request
1200 * is in proper (pre-alloc'd) request buffer range...
1201 */
1202 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1203 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1204 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1205 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301206 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 }
1208
1209 /* Make sure there are no doorbells */
1210 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001211
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1213 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1214 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1215
1216 /* Wait for IOC doorbell int */
1217 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1218 return ii;
1219 }
1220
1221 /* Read doorbell and check for active bit */
1222 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1223 return -5;
1224
Eric Moore29dd3602007-09-14 18:46:51 -06001225 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001226 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227
1228 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1229
1230 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1231 return -2;
1232 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001233
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 /* Send request via doorbell handshake */
1235 req_as_bytes = (u8 *) req;
1236 for (ii = 0; ii < reqBytes/4; ii++) {
1237 u32 word;
1238
1239 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1240 (req_as_bytes[(ii*4) + 1] << 8) |
1241 (req_as_bytes[(ii*4) + 2] << 16) |
1242 (req_as_bytes[(ii*4) + 3] << 24));
1243 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1244 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1245 r = -3;
1246 break;
1247 }
1248 }
1249
1250 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1251 r = 0;
1252 else
1253 r = -4;
1254
1255 /* Make sure there are no doorbells */
1256 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001257
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 return r;
1259}
1260
1261/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1262/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001263 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001264 * @ioc: Pointer to MPT adapter structure
1265 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001266 * @sleepFlag: Specifies whether the process can sleep
1267 *
1268 * Provides mechanism for the host driver to control the IOC's
1269 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001270 *
1271 * Access Control Value - bits[15:12]
1272 * 0h Reserved
1273 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1274 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1275 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1276 *
1277 * Returns 0 for success, non-zero for failure.
1278 */
1279
1280static int
1281mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1282{
1283 int r = 0;
1284
1285 /* return if in use */
1286 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1287 & MPI_DOORBELL_ACTIVE)
1288 return -1;
1289
1290 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1291
1292 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1293 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1294 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1295 (access_control_value<<12)));
1296
1297 /* Wait for IOC to clear Doorbell Status bit */
1298 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1299 return -2;
1300 }else
1301 return 0;
1302}
1303
1304/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1305/**
1306 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001307 * @ioc: Pointer to pointer to IOC adapter
1308 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001309 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001310 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001311 * Returns 0 for success, non-zero for failure.
1312 */
1313static int
1314mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1315{
1316 char *psge;
1317 int flags_length;
1318 u32 host_page_buffer_sz=0;
1319
1320 if(!ioc->HostPageBuffer) {
1321
1322 host_page_buffer_sz =
1323 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1324
1325 if(!host_page_buffer_sz)
1326 return 0; /* fw doesn't need any host buffers */
1327
1328 /* spin till we get enough memory */
1329 while(host_page_buffer_sz > 0) {
1330
1331 if((ioc->HostPageBuffer = pci_alloc_consistent(
1332 ioc->pcidev,
1333 host_page_buffer_sz,
1334 &ioc->HostPageBuffer_dma)) != NULL) {
1335
Prakash, Sathya436ace72007-07-24 15:42:08 +05301336 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001337 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001338 ioc->name, ioc->HostPageBuffer,
1339 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001340 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001341 ioc->alloc_total += host_page_buffer_sz;
1342 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1343 break;
1344 }
1345
1346 host_page_buffer_sz -= (4*1024);
1347 }
1348 }
1349
1350 if(!ioc->HostPageBuffer) {
1351 printk(MYIOC_s_ERR_FMT
1352 "Failed to alloc memory for host_page_buffer!\n",
1353 ioc->name);
1354 return -999;
1355 }
1356
1357 psge = (char *)&ioc_init->HostPageBufferSGE;
1358 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1359 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001360 MPI_SGE_FLAGS_HOST_TO_IOC |
1361 MPI_SGE_FLAGS_END_OF_BUFFER;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001362 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1363 flags_length |= ioc->HostPageBuffer_sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301364 ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001365 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1366
1367return 0;
1368}
1369
1370/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1371/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001372 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 * @iocid: IOC unique identifier (integer)
1374 * @iocpp: Pointer to pointer to IOC adapter
1375 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001376 * Given a unique IOC identifier, set pointer to the associated MPT
1377 * adapter structure.
1378 *
1379 * Returns iocid and sets iocpp if iocid is found.
1380 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 */
1382int
1383mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1384{
1385 MPT_ADAPTER *ioc;
1386
1387 list_for_each_entry(ioc,&ioc_list,list) {
1388 if (ioc->id == iocid) {
1389 *iocpp =ioc;
1390 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001391 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001393
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 *iocpp = NULL;
1395 return -1;
1396}
1397
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301398/**
1399 * mpt_get_product_name - returns product string
1400 * @vendor: pci vendor id
1401 * @device: pci device id
1402 * @revision: pci revision id
1403 * @prod_name: string returned
1404 *
1405 * Returns product string displayed when driver loads,
1406 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1407 *
1408 **/
Joe Lawrencec9834c72014-06-25 17:06:28 -04001409static const char*
1410mpt_get_product_name(u16 vendor, u16 device, u8 revision)
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301411{
1412 char *product_str = NULL;
1413
1414 if (vendor == PCI_VENDOR_ID_BROCADE) {
1415 switch (device)
1416 {
1417 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1418 switch (revision)
1419 {
1420 case 0x00:
1421 product_str = "BRE040 A0";
1422 break;
1423 case 0x01:
1424 product_str = "BRE040 A1";
1425 break;
1426 default:
1427 product_str = "BRE040";
1428 break;
1429 }
1430 break;
1431 }
1432 goto out;
1433 }
1434
1435 switch (device)
1436 {
1437 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1438 product_str = "LSIFC909 B1";
1439 break;
1440 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1441 product_str = "LSIFC919 B0";
1442 break;
1443 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1444 product_str = "LSIFC929 B0";
1445 break;
1446 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1447 if (revision < 0x80)
1448 product_str = "LSIFC919X A0";
1449 else
1450 product_str = "LSIFC919XL A1";
1451 break;
1452 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1453 if (revision < 0x80)
1454 product_str = "LSIFC929X A0";
1455 else
1456 product_str = "LSIFC929XL A1";
1457 break;
1458 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1459 product_str = "LSIFC939X A1";
1460 break;
1461 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1462 product_str = "LSIFC949X A1";
1463 break;
1464 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1465 switch (revision)
1466 {
1467 case 0x00:
1468 product_str = "LSIFC949E A0";
1469 break;
1470 case 0x01:
1471 product_str = "LSIFC949E A1";
1472 break;
1473 default:
1474 product_str = "LSIFC949E";
1475 break;
1476 }
1477 break;
1478 case MPI_MANUFACTPAGE_DEVID_53C1030:
1479 switch (revision)
1480 {
1481 case 0x00:
1482 product_str = "LSI53C1030 A0";
1483 break;
1484 case 0x01:
1485 product_str = "LSI53C1030 B0";
1486 break;
1487 case 0x03:
1488 product_str = "LSI53C1030 B1";
1489 break;
1490 case 0x07:
1491 product_str = "LSI53C1030 B2";
1492 break;
1493 case 0x08:
1494 product_str = "LSI53C1030 C0";
1495 break;
1496 case 0x80:
1497 product_str = "LSI53C1030T A0";
1498 break;
1499 case 0x83:
1500 product_str = "LSI53C1030T A2";
1501 break;
1502 case 0x87:
1503 product_str = "LSI53C1030T A3";
1504 break;
1505 case 0xc1:
1506 product_str = "LSI53C1020A A1";
1507 break;
1508 default:
1509 product_str = "LSI53C1030";
1510 break;
1511 }
1512 break;
1513 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1514 switch (revision)
1515 {
1516 case 0x03:
1517 product_str = "LSI53C1035 A2";
1518 break;
1519 case 0x04:
1520 product_str = "LSI53C1035 B0";
1521 break;
1522 default:
1523 product_str = "LSI53C1035";
1524 break;
1525 }
1526 break;
1527 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1528 switch (revision)
1529 {
1530 case 0x00:
1531 product_str = "LSISAS1064 A1";
1532 break;
1533 case 0x01:
1534 product_str = "LSISAS1064 A2";
1535 break;
1536 case 0x02:
1537 product_str = "LSISAS1064 A3";
1538 break;
1539 case 0x03:
1540 product_str = "LSISAS1064 A4";
1541 break;
1542 default:
1543 product_str = "LSISAS1064";
1544 break;
1545 }
1546 break;
1547 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1548 switch (revision)
1549 {
1550 case 0x00:
1551 product_str = "LSISAS1064E A0";
1552 break;
1553 case 0x01:
1554 product_str = "LSISAS1064E B0";
1555 break;
1556 case 0x02:
1557 product_str = "LSISAS1064E B1";
1558 break;
1559 case 0x04:
1560 product_str = "LSISAS1064E B2";
1561 break;
1562 case 0x08:
1563 product_str = "LSISAS1064E B3";
1564 break;
1565 default:
1566 product_str = "LSISAS1064E";
1567 break;
1568 }
1569 break;
1570 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1571 switch (revision)
1572 {
1573 case 0x00:
1574 product_str = "LSISAS1068 A0";
1575 break;
1576 case 0x01:
1577 product_str = "LSISAS1068 B0";
1578 break;
1579 case 0x02:
1580 product_str = "LSISAS1068 B1";
1581 break;
1582 default:
1583 product_str = "LSISAS1068";
1584 break;
1585 }
1586 break;
1587 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1588 switch (revision)
1589 {
1590 case 0x00:
1591 product_str = "LSISAS1068E A0";
1592 break;
1593 case 0x01:
1594 product_str = "LSISAS1068E B0";
1595 break;
1596 case 0x02:
1597 product_str = "LSISAS1068E B1";
1598 break;
1599 case 0x04:
1600 product_str = "LSISAS1068E B2";
1601 break;
1602 case 0x08:
1603 product_str = "LSISAS1068E B3";
1604 break;
1605 default:
1606 product_str = "LSISAS1068E";
1607 break;
1608 }
1609 break;
1610 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1611 switch (revision)
1612 {
1613 case 0x00:
1614 product_str = "LSISAS1078 A0";
1615 break;
1616 case 0x01:
1617 product_str = "LSISAS1078 B0";
1618 break;
1619 case 0x02:
1620 product_str = "LSISAS1078 C0";
1621 break;
1622 case 0x03:
1623 product_str = "LSISAS1078 C1";
1624 break;
1625 case 0x04:
1626 product_str = "LSISAS1078 C2";
1627 break;
1628 default:
1629 product_str = "LSISAS1078";
1630 break;
1631 }
1632 break;
1633 }
1634
1635 out:
Joe Lawrencec9834c72014-06-25 17:06:28 -04001636 return product_str;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301637}
1638
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301639/**
1640 * mpt_mapresources - map in memory mapped io
1641 * @ioc: Pointer to pointer to IOC adapter
1642 *
1643 **/
1644static int
1645mpt_mapresources(MPT_ADAPTER *ioc)
1646{
1647 u8 __iomem *mem;
1648 int ii;
Pravin Bathijae46b63b2009-12-02 17:51:46 -08001649 resource_size_t mem_phys;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301650 unsigned long port;
1651 u32 msize;
1652 u32 psize;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301653 int r = -ENODEV;
1654 struct pci_dev *pdev;
1655
1656 pdev = ioc->pcidev;
1657 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1658 if (pci_enable_device_mem(pdev)) {
1659 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1660 "failed\n", ioc->name);
1661 return r;
1662 }
1663 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1664 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1665 "MEM failed\n", ioc->name);
Hanjun Guo20953a62012-08-11 10:58:36 +08001666 goto out_pci_disable_device;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301667 }
1668
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301669 if (sizeof(dma_addr_t) > 4) {
1670 const uint64_t required_mask = dma_get_required_mask
1671 (&pdev->dev);
1672 if (required_mask > DMA_BIT_MASK(32)
1673 && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
1674 && !pci_set_consistent_dma_mask(pdev,
1675 DMA_BIT_MASK(64))) {
1676 ioc->dma_mask = DMA_BIT_MASK(64);
1677 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1678 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1679 ioc->name));
1680 } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1681 && !pci_set_consistent_dma_mask(pdev,
1682 DMA_BIT_MASK(32))) {
1683 ioc->dma_mask = DMA_BIT_MASK(32);
1684 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1685 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1686 ioc->name));
1687 } else {
1688 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1689 ioc->name, pci_name(pdev));
Hanjun Guo20953a62012-08-11 10:58:36 +08001690 goto out_pci_release_region;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301691 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301692 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301693 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1694 && !pci_set_consistent_dma_mask(pdev,
1695 DMA_BIT_MASK(32))) {
1696 ioc->dma_mask = DMA_BIT_MASK(32);
1697 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1698 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1699 ioc->name));
1700 } else {
1701 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1702 ioc->name, pci_name(pdev));
Hanjun Guo20953a62012-08-11 10:58:36 +08001703 goto out_pci_release_region;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301704 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301705 }
1706
1707 mem_phys = msize = 0;
1708 port = psize = 0;
1709 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1710 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1711 if (psize)
1712 continue;
1713 /* Get I/O space! */
1714 port = pci_resource_start(pdev, ii);
1715 psize = pci_resource_len(pdev, ii);
1716 } else {
1717 if (msize)
1718 continue;
1719 /* Get memmap */
1720 mem_phys = pci_resource_start(pdev, ii);
1721 msize = pci_resource_len(pdev, ii);
1722 }
1723 }
1724 ioc->mem_size = msize;
1725
1726 mem = NULL;
1727 /* Get logical ptr for PciMem0 space */
1728 /*mem = ioremap(mem_phys, msize);*/
1729 mem = ioremap(mem_phys, msize);
1730 if (mem == NULL) {
1731 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1732 " memory!\n", ioc->name);
Hanjun Guo20953a62012-08-11 10:58:36 +08001733 r = -EINVAL;
1734 goto out_pci_release_region;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301735 }
1736 ioc->memmap = mem;
Pravin Bathijae46b63b2009-12-02 17:51:46 -08001737 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %llx\n",
1738 ioc->name, mem, (unsigned long long)mem_phys));
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301739
1740 ioc->mem_phys = mem_phys;
1741 ioc->chip = (SYSIF_REGS __iomem *)mem;
1742
1743 /* Save Port IO values in case we need to do downloadboot */
1744 ioc->pio_mem_phys = port;
1745 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1746
1747 return 0;
Hanjun Guo20953a62012-08-11 10:58:36 +08001748
1749out_pci_release_region:
1750 pci_release_selected_regions(pdev, ioc->bars);
1751out_pci_disable_device:
1752 pci_disable_device(pdev);
1753 return r;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301754}
1755
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001757/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001758 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001760 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 *
1762 * This routine performs all the steps necessary to bring the IOC of
1763 * a MPT adapter to a OPERATIONAL state. This includes registering
1764 * memory regions, registering the interrupt, and allocating request
1765 * and reply memory pools.
1766 *
1767 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1768 * MPT adapter.
1769 *
1770 * Returns 0 for success, non-zero for failure.
1771 *
1772 * TODO: Add support for polled controllers
1773 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001774int
1775mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776{
1777 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301778 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 u8 pcixcmd;
1781 static int mpt_ids = 0;
1782#ifdef CONFIG_PROC_FS
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07001783 struct proc_dir_entry *dent;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784#endif
1785
Jesper Juhl56876192007-08-10 14:50:51 -07001786 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1787 if (ioc == NULL) {
1788 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1789 return -ENOMEM;
1790 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301791
Eric Moore29dd3602007-09-14 18:46:51 -06001792 ioc->id = mpt_ids++;
1793 sprintf(ioc->name, "ioc%d", ioc->id);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301794 dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Jesper Juhl56876192007-08-10 14:50:51 -07001795
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301796 /*
1797 * set initial debug level
1798 * (refer to mptdebug.h)
1799 *
1800 */
1801 ioc->debug_level = mpt_debug_level;
1802 if (mpt_debug_level)
1803 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301804
Eric Moore29dd3602007-09-14 18:46:51 -06001805 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001806
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301807 ioc->pcidev = pdev;
1808 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001809 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 return r;
1811 }
1812
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301813 /*
1814 * Setting up proper handlers for scatter gather handling
1815 */
1816 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
1817 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
1818 ioc->add_sge = &mpt_add_sge_64bit_1078;
1819 else
1820 ioc->add_sge = &mpt_add_sge_64bit;
1821 ioc->add_chain = &mpt_add_chain_64bit;
1822 ioc->sg_addr_size = 8;
1823 } else {
1824 ioc->add_sge = &mpt_add_sge;
1825 ioc->add_chain = &mpt_add_chain;
1826 ioc->sg_addr_size = 4;
1827 }
1828 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
1829
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 ioc->alloc_total = sizeof(MPT_ADAPTER);
1831 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1832 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001833
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301835 spin_lock_init(&ioc->taskmgmt_lock);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05301836 mutex_init(&ioc->internal_cmds.mutex);
1837 init_completion(&ioc->internal_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301838 mutex_init(&ioc->mptbase_cmds.mutex);
1839 init_completion(&ioc->mptbase_cmds.done);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301840 mutex_init(&ioc->taskmgmt_cmds.mutex);
1841 init_completion(&ioc->taskmgmt_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301842
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 /* Initialize the event logging.
1844 */
1845 ioc->eventTypes = 0; /* None */
1846 ioc->eventContext = 0;
1847 ioc->eventLogSize = 0;
1848 ioc->events = NULL;
1849
1850#ifdef MFCNT
1851 ioc->mfcnt = 0;
1852#endif
1853
Kashyap, Desai2f187862009-05-29 16:52:37 +05301854 ioc->sh = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 ioc->cached_fw = NULL;
1856
Uwe Kleine-König421f91d2010-06-11 12:17:00 +02001857 /* Initialize SCSI Config Data structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001859 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860
Michael Reed05e8ec12006-01-13 14:31:54 -06001861 /* Initialize the fc rport list head.
1862 */
1863 INIT_LIST_HEAD(&ioc->fc_rports);
1864
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 /* Find lookup slot. */
1866 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001867
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301868
1869 /* Initialize workqueue */
1870 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301871
Kashyap, Desai2f187862009-05-29 16:52:37 +05301872 snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN,
Kay Sieversaab0de22008-05-02 06:02:41 +02001873 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301874 ioc->reset_work_q =
1875 create_singlethread_workqueue(ioc->reset_work_q_name);
1876 if (!ioc->reset_work_q) {
1877 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1878 ioc->name);
1879 pci_release_selected_regions(pdev, ioc->bars);
1880 kfree(ioc);
1881 return -ENOMEM;
1882 }
1883
Eric Moore29dd3602007-09-14 18:46:51 -06001884 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1885 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886
Joe Lawrencec9834c72014-06-25 17:06:28 -04001887 ioc->prod_name = mpt_get_product_name(pdev->vendor, pdev->device,
1888 pdev->revision);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301889
1890 switch (pdev->device)
1891 {
1892 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1893 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1894 ioc->errata_flag_1064 = 1;
1895 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1896 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1897 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1898 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301900 break;
1901
1902 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Sergei Shtylyov9ceb5c12012-05-31 16:26:06 -07001903 if (pdev->revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 /* 929X Chip Fix. Set Split transactions level
1905 * for PCIX. Set MOST bits to zero.
1906 */
1907 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1908 pcixcmd &= 0x8F;
1909 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1910 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 /* 929XL Chip Fix. Set MMRBC to 0x08.
1912 */
1913 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1914 pcixcmd |= 0x08;
1915 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1916 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301918 break;
1919
1920 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 /* 919X Chip Fix. Set Split transactions level
1922 * for PCIX. Set MOST bits to zero.
1923 */
1924 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1925 pcixcmd &= 0x8F;
1926 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001927 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301928 break;
1929
1930 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 /* 1030 Chip Fix. Disable Split transactions
1932 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1933 */
Sergei Shtylyov9ceb5c12012-05-31 16:26:06 -07001934 if (pdev->revision < C0_1030) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1936 pcixcmd &= 0x8F;
1937 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1938 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301939
1940 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001941 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301942 break;
1943
1944 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1945 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001946 ioc->errata_flag_1064 = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301947 ioc->bus_type = SAS;
1948 break;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301949
1950 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1951 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1952 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001953 ioc->bus_type = SAS;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301954 break;
Eric Moore87cf8982006-06-27 16:09:26 -06001955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301957
Kashyap, Desaie3829682009-01-08 14:27:16 +05301958 switch (ioc->bus_type) {
1959
1960 case SAS:
1961 ioc->msi_enable = mpt_msi_enable_sas;
1962 break;
1963
1964 case SPI:
1965 ioc->msi_enable = mpt_msi_enable_spi;
1966 break;
1967
1968 case FC:
1969 ioc->msi_enable = mpt_msi_enable_fc;
1970 break;
1971
1972 default:
1973 ioc->msi_enable = 0;
1974 break;
1975 }
Kashyap, Desai8ce13de2010-06-17 14:35:46 +05301976
1977 ioc->fw_events_off = 1;
1978
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001979 if (ioc->errata_flag_1064)
1980 pci_disable_io_access(pdev);
1981
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 spin_lock_init(&ioc->FreeQlock);
1983
1984 /* Disable all! */
1985 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1986 ioc->active = 0;
1987 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1988
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301989 /* Set IOC ptr in the pcidev's driver data. */
1990 pci_set_drvdata(ioc->pcidev, ioc);
1991
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 /* Set lookup ptr. */
1993 list_add_tail(&ioc->list, &ioc_list);
1994
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001995 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 */
1997 mpt_detect_bound_ports(ioc, pdev);
1998
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301999 INIT_LIST_HEAD(&ioc->fw_event_list);
2000 spin_lock_init(&ioc->fw_event_lock);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302001 snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05302002 ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
2003
James Bottomleyc92f2222006-03-01 09:02:49 -06002004 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2005 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06002006 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
2007 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06002008
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07002010 if (ioc->alt_ioc)
2011 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302012 iounmap(ioc->memmap);
2013 if (r != -5)
2014 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302015
2016 destroy_workqueue(ioc->reset_work_q);
2017 ioc->reset_work_q = NULL;
2018
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 kfree(ioc);
2020 pci_set_drvdata(pdev, NULL);
2021 return r;
2022 }
2023
2024 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002025 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302026 if(MptDeviceDriverHandlers[cb_idx] &&
2027 MptDeviceDriverHandlers[cb_idx]->probe) {
2028 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 }
2030 }
2031
2032#ifdef CONFIG_PROC_FS
2033 /*
2034 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
2035 */
2036 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
2037 if (dent) {
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07002038 proc_create_data("info", S_IRUGO, dent, &mpt_iocinfo_proc_fops, ioc);
2039 proc_create_data("summary", S_IRUGO, dent, &mpt_summary_proc_fops, ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 }
2041#endif
2042
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302043 if (!ioc->alt_ioc)
2044 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
2045 msecs_to_jiffies(MPT_POLLING_INTERVAL));
2046
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 return 0;
2048}
2049
2050/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002051/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002052 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 */
2055
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002056void
2057mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058{
2059 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2060 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302061 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302062 unsigned long flags;
2063 struct workqueue_struct *wq;
2064
2065 /*
2066 * Stop polling ioc for fault condition
2067 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302068 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302069 wq = ioc->reset_work_q;
2070 ioc->reset_work_q = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302071 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302072 cancel_delayed_work(&ioc->fault_reset_work);
2073 destroy_workqueue(wq);
2074
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05302075 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2076 wq = ioc->fw_event_q;
2077 ioc->fw_event_q = NULL;
2078 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2079 destroy_workqueue(wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080
2081 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2082 remove_proc_entry(pname, NULL);
2083 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2084 remove_proc_entry(pname, NULL);
2085 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2086 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002087
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002089 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302090 if(MptDeviceDriverHandlers[cb_idx] &&
2091 MptDeviceDriverHandlers[cb_idx]->remove) {
2092 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 }
2094 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002095
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 /* Disable interrupts! */
2097 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2098
2099 ioc->active = 0;
2100 synchronize_irq(pdev->irq);
2101
2102 /* Clear any lingering interrupt */
2103 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2104
2105 CHIPREG_READ32(&ioc->chip->IntStatus);
2106
2107 mpt_adapter_dispose(ioc);
2108
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109}
2110
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111/**************************************************************************
2112 * Power Management
2113 */
2114#ifdef CONFIG_PM
2115/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002116/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002117 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002118 * @pdev: Pointer to pci_dev structure
2119 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002121int
2122mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123{
2124 u32 device_state;
2125 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302127 device_state = pci_choose_state(pdev, state);
2128 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2129 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2130 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131
2132 /* put ioc into READY_STATE */
2133 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2134 printk(MYIOC_s_ERR_FMT
2135 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2136 }
2137
2138 /* disable interrupts */
2139 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2140 ioc->active = 0;
2141
2142 /* Clear any lingering interrupt */
2143 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2144
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302145 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002146 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302147 pci_disable_msi(ioc->pcidev);
2148 ioc->pci_irq = -1;
2149 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302151 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 return 0;
2154}
2155
2156/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002157/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002158 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002159 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002161int
2162mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163{
2164 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2165 u32 device_state = pdev->current_state;
2166 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302167 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002168
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302169 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2170 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2171 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302173 pci_set_power_state(pdev, PCI_D0);
2174 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302176 ioc->pcidev = pdev;
2177 err = mpt_mapresources(ioc);
2178 if (err)
2179 return err;
2180
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302181 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2182 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2183 ioc->add_sge = &mpt_add_sge_64bit_1078;
2184 else
2185 ioc->add_sge = &mpt_add_sge_64bit;
2186 ioc->add_chain = &mpt_add_chain_64bit;
2187 ioc->sg_addr_size = 8;
2188 } else {
2189
2190 ioc->add_sge = &mpt_add_sge;
2191 ioc->add_chain = &mpt_add_chain;
2192 ioc->sg_addr_size = 4;
2193 }
2194 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2195
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302196 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2197 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2198 CHIPREG_READ32(&ioc->chip->Doorbell));
2199
2200 /*
2201 * Errata workaround for SAS pci express:
2202 * Upon returning to the D0 state, the contents of the doorbell will be
2203 * stale data, and this will incorrectly signal to the host driver that
2204 * the firmware is ready to process mpt commands. The workaround is
2205 * to issue a diagnostic reset.
2206 */
2207 if (ioc->bus_type == SAS && (pdev->device ==
2208 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2209 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2210 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2211 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2212 ioc->name);
2213 goto out;
2214 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302215 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216
2217 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302218 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2219 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2220 CAN_SLEEP);
2221 if (recovery_state != 0)
2222 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2223 "error:[%x]\n", ioc->name, recovery_state);
2224 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302226 "pci-resume: success\n", ioc->name);
2227 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302229
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230}
2231#endif
2232
James Bottomley4ff42a62006-05-17 18:06:52 -05002233static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302234mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002235{
2236 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2237 ioc->bus_type != SPI) ||
2238 (MptDriverClass[index] == MPTFC_DRIVER &&
2239 ioc->bus_type != FC) ||
2240 (MptDriverClass[index] == MPTSAS_DRIVER &&
2241 ioc->bus_type != SAS))
2242 /* make sure we only call the relevant reset handler
2243 * for the bus */
2244 return 0;
2245 return (MptResetHandlers[index])(ioc, reset_phase);
2246}
2247
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002249/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2251 * @ioc: Pointer to MPT adapter structure
2252 * @reason: Event word / reason
2253 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2254 *
2255 * This routine performs all the steps necessary to bring the IOC
2256 * to a OPERATIONAL state.
2257 *
2258 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2259 * MPT adapter.
2260 *
2261 * Returns:
2262 * 0 for success
2263 * -1 if failed to get board READY
2264 * -2 if READY but IOCFacts Failed
2265 * -3 if READY but PrimeIOCFifos Failed
2266 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302267 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302268 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 */
2270static int
2271mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2272{
2273 int hard_reset_done = 0;
2274 int alt_ioc_ready = 0;
2275 int hard;
2276 int rc=0;
2277 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 int ret = 0;
2279 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002280 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302281 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282
Eric Moore29dd3602007-09-14 18:46:51 -06002283 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2284 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285
2286 /* Disable reply interrupts (also blocks FreeQ) */
2287 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2288 ioc->active = 0;
2289
2290 if (ioc->alt_ioc) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302291 if (ioc->alt_ioc->active ||
2292 reason == MPT_HOSTEVENT_IOC_RECOVER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 reset_alt_ioc_active = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302294 /* Disable alt-IOC's reply interrupts
2295 * (and FreeQ) for a bit
2296 **/
2297 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2298 0xFFFFFFFF);
2299 ioc->alt_ioc->active = 0;
2300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 }
2302
2303 hard = 1;
2304 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2305 hard = 0;
2306
2307 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2308 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002309 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2310 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311
2312 if (reset_alt_ioc_active && ioc->alt_ioc) {
2313 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002314 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2315 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002316 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 ioc->alt_ioc->active = 1;
2318 }
2319
2320 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302321 printk(MYIOC_s_WARN_FMT
2322 "NOT READY WARNING!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302324 ret = -1;
2325 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 }
2327
2328 /* hard_reset_done = 0 if a soft reset was performed
2329 * and 1 if a hard reset was performed.
2330 */
2331 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2332 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2333 alt_ioc_ready = 1;
2334 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05302335 printk(MYIOC_s_WARN_FMT
2336 ": alt-ioc Not ready WARNING!\n",
2337 ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 }
2339
2340 for (ii=0; ii<5; ii++) {
2341 /* Get IOC facts! Allow 5 retries */
2342 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2343 break;
2344 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002345
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346
2347 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002348 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2349 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 ret = -2;
2351 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2352 MptDisplayIocCapabilities(ioc);
2353 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002354
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 if (alt_ioc_ready) {
2356 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302357 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302358 "Initial Alt IocFacts failed rc=%x\n",
2359 ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 /* Retry - alt IOC was initialized once
2361 */
2362 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2363 }
2364 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302365 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002366 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 alt_ioc_ready = 0;
2368 reset_alt_ioc_active = 0;
2369 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2370 MptDisplayIocCapabilities(ioc->alt_ioc);
2371 }
2372 }
2373
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302374 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2375 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2376 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2377 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2378 IORESOURCE_IO);
2379 if (pci_enable_device(ioc->pcidev))
2380 return -5;
2381 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2382 "mpt"))
2383 return -5;
2384 }
2385
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002386 /*
2387 * Device is reset now. It must have de-asserted the interrupt line
2388 * (if it was asserted) and it should be safe to register for the
2389 * interrupt now.
2390 */
2391 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2392 ioc->pci_irq = -1;
2393 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302394 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002395 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002396 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302397 else
2398 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002399 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002400 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002401 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002402 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Kashyap, Desai2f187862009-05-29 16:52:37 +05302403 "interrupt %d!\n",
2404 ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302405 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002406 pci_disable_msi(ioc->pcidev);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302407 ret = -EBUSY;
2408 goto out;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002409 }
2410 irq_allocated = 1;
2411 ioc->pci_irq = ioc->pcidev->irq;
2412 pci_set_master(ioc->pcidev); /* ?? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302413 pci_set_drvdata(ioc->pcidev, ioc);
2414 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2415 "installed at interrupt %d\n", ioc->name,
2416 ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002417 }
2418 }
2419
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 /* Prime reply & request queues!
2421 * (mucho alloc's) Must be done prior to
2422 * init as upper addresses are needed for init.
2423 * If fails, continue with alt-ioc processing
2424 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302425 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
2426 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2428 ret = -3;
2429
2430 /* May need to check/upload firmware & data here!
2431 * If fails, continue with alt-ioc processing
2432 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302433 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
2434 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2436 ret = -4;
2437// NEW!
2438 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302439 printk(MYIOC_s_WARN_FMT
2440 ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002441 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 alt_ioc_ready = 0;
2443 reset_alt_ioc_active = 0;
2444 }
2445
2446 if (alt_ioc_ready) {
2447 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2448 alt_ioc_ready = 0;
2449 reset_alt_ioc_active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302450 printk(MYIOC_s_WARN_FMT
2451 ": alt-ioc: (%d) init failure WARNING!\n",
2452 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 }
2454 }
2455
2456 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2457 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302458 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002459 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460
2461 /* Controller is not operational, cannot do upload
2462 */
2463 if (ret == 0) {
2464 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002465 if (rc == 0) {
2466 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2467 /*
2468 * Maintain only one pointer to FW memory
2469 * so there will not be two attempt to
2470 * downloadboot onboard dual function
2471 * chips (mpt_adapter_disable,
2472 * mpt_diag_reset)
2473 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302474 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002475 "mpt_upload: alt_%s has cached_fw=%p \n",
2476 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302477 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002478 }
2479 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002480 printk(MYIOC_s_WARN_FMT
2481 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302482 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002483 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 }
2485 }
2486 }
2487
Kashyap, Desaifd761752009-05-29 16:39:06 +05302488 /* Enable MPT base driver management of EventNotification
2489 * and EventAck handling.
2490 */
2491 if ((ret == 0) && (!ioc->facts.EventState)) {
2492 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2493 "SendEventNotification\n",
2494 ioc->name));
2495 ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
2496 }
2497
2498 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2499 rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
2500
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 if (ret == 0) {
2502 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002503 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 ioc->active = 1;
2505 }
Kashyap, Desaifd761752009-05-29 16:39:06 +05302506 if (rc == 0) { /* alt ioc */
2507 if (reset_alt_ioc_active && ioc->alt_ioc) {
2508 /* (re)Enable alt-IOC! (reply interrupt) */
2509 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
2510 "reply irq re-enabled\n",
2511 ioc->alt_ioc->name));
2512 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2513 MPI_HIM_DIM);
2514 ioc->alt_ioc->active = 1;
2515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 }
2517
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002519 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2521 * recursive scenario; GetLanConfigPages times out, timer expired
2522 * routine calls HardResetHandler, which calls into here again,
2523 * and we try GetLanConfigPages again...
2524 */
2525 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002526
2527 /*
Uwe Kleine-König421f91d2010-06-11 12:17:00 +02002528 * Initialize link list for inactive raid volumes.
Eric Mooreb506ade2007-01-29 09:45:37 -07002529 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002530 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002531 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2532
Kashyap, Desai2f187862009-05-29 16:52:37 +05302533 switch (ioc->bus_type) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002534
Kashyap, Desai2f187862009-05-29 16:52:37 +05302535 case SAS:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002536 /* clear persistency table */
2537 if(ioc->facts.IOCExceptions &
2538 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2539 ret = mptbase_sas_persist_operation(ioc,
2540 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2541 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002542 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002543 }
2544
2545 /* Find IM volumes
2546 */
2547 mpt_findImVolumes(ioc);
2548
Kashyap, Desai2f187862009-05-29 16:52:37 +05302549 /* Check, and possibly reset, the coalescing value
2550 */
2551 mpt_read_ioc_pg_1(ioc);
2552
2553 break;
2554
2555 case FC:
2556 if ((ioc->pfacts[0].ProtocolFlags &
2557 MPI_PORTFACTS_PROTOCOL_LAN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2559 /*
2560 * Pre-fetch the ports LAN MAC address!
2561 * (LANPage1_t stuff)
2562 */
2563 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302564 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2565 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302566 "LanAddr = %02X:%02X:%02X"
2567 ":%02X:%02X:%02X\n",
2568 ioc->name, a[5], a[4],
2569 a[3], a[2], a[1], a[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302571 break;
2572
2573 case SPI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 /* Get NVRAM and adapter maximums from SPP 0 and 2
2575 */
2576 mpt_GetScsiPortSettings(ioc, 0);
2577
2578 /* Get version and length of SDP 1
2579 */
2580 mpt_readScsiDevicePageHeaders(ioc, 0);
2581
2582 /* Find IM volumes
2583 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002584 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 mpt_findImVolumes(ioc);
2586
2587 /* Check, and possibly reset, the coalescing value
2588 */
2589 mpt_read_ioc_pg_1(ioc);
2590
2591 mpt_read_ioc_pg_4(ioc);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302592
2593 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 }
2595
2596 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302597 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 }
2599
Eric Moore0ccdb002006-07-11 17:33:13 -06002600 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002601 if ((ret != 0) && irq_allocated) {
2602 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302603 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002604 pci_disable_msi(ioc->pcidev);
2605 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 return ret;
2607}
2608
2609/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002610/**
2611 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 * @ioc: Pointer to MPT adapter structure
2613 * @pdev: Pointer to (struct pci_dev) structure
2614 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002615 * Search for PCI bus/dev_function which matches
2616 * PCI bus/dev_function (+/-1) for newly discovered 929,
2617 * 929X, 1030 or 1035.
2618 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2620 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2621 */
2622static void
2623mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2624{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002625 struct pci_dev *peer=NULL;
2626 unsigned int slot = PCI_SLOT(pdev->devfn);
2627 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 MPT_ADAPTER *ioc_srch;
2629
Prakash, Sathya436ace72007-07-24 15:42:08 +05302630 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002631 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002632 ioc->name, pci_name(pdev), pdev->bus->number,
2633 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002634
2635 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2636 if (!peer) {
2637 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2638 if (!peer)
2639 return;
2640 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641
2642 list_for_each_entry(ioc_srch, &ioc_list, list) {
2643 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002644 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 /* Paranoia checks */
2646 if (ioc->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302647 printk(MYIOC_s_WARN_FMT
2648 "Oops, already bound (%s <==> %s)!\n",
2649 ioc->name, ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 break;
2651 } else if (ioc_srch->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302652 printk(MYIOC_s_WARN_FMT
2653 "Oops, already bound (%s <==> %s)!\n",
2654 ioc_srch->name, ioc_srch->name,
2655 ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 break;
2657 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302658 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2659 "FOUND! binding %s <==> %s\n",
2660 ioc->name, ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 ioc_srch->alt_ioc = ioc;
2662 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 }
2664 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002665 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666}
2667
2668/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002669/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002671 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 */
2673static void
2674mpt_adapter_disable(MPT_ADAPTER *ioc)
2675{
2676 int sz;
2677 int ret;
2678
2679 if (ioc->cached_fw != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302680 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2681 "%s: Pushing FW onto adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302682 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2683 ioc->cached_fw, CAN_SLEEP)) < 0) {
2684 printk(MYIOC_s_WARN_FMT
2685 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002686 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 }
2688 }
2689
Kashyap, Desai71278192009-05-29 16:53:14 +05302690 /*
2691 * Put the controller into ready state (if its not already)
2692 */
2693 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {
2694 if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
2695 CAN_SLEEP)) {
2696 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)
2697 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit "
2698 "reset failed to put ioc in ready state!\n",
2699 ioc->name, __func__);
2700 } else
2701 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset "
2702 "failed!\n", ioc->name, __func__);
2703 }
2704
2705
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 /* Disable adapter interrupts! */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302707 synchronize_irq(ioc->pcidev->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2709 ioc->active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302710
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 /* Clear any lingering interrupt */
2712 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302713 CHIPREG_READ32(&ioc->chip->IntStatus);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714
2715 if (ioc->alloc != NULL) {
2716 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002717 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2718 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 pci_free_consistent(ioc->pcidev, sz,
2720 ioc->alloc, ioc->alloc_dma);
2721 ioc->reply_frames = NULL;
2722 ioc->req_frames = NULL;
2723 ioc->alloc = NULL;
2724 ioc->alloc_total -= sz;
2725 }
2726
2727 if (ioc->sense_buf_pool != NULL) {
2728 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2729 pci_free_consistent(ioc->pcidev, sz,
2730 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2731 ioc->sense_buf_pool = NULL;
2732 ioc->alloc_total -= sz;
2733 }
2734
2735 if (ioc->events != NULL){
2736 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2737 kfree(ioc->events);
2738 ioc->events = NULL;
2739 ioc->alloc_total -= sz;
2740 }
2741
Prakash, Sathya984621b2008-01-11 14:42:17 +05302742 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002744 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002745 mpt_inactive_raid_list_free(ioc);
2746 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002747 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002748 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002749 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750
2751 if (ioc->spi_data.pIocPg4 != NULL) {
2752 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302753 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 ioc->spi_data.pIocPg4,
2755 ioc->spi_data.IocPg4_dma);
2756 ioc->spi_data.pIocPg4 = NULL;
2757 ioc->alloc_total -= sz;
2758 }
2759
2760 if (ioc->ReqToChain != NULL) {
2761 kfree(ioc->ReqToChain);
2762 kfree(ioc->RequestNB);
2763 ioc->ReqToChain = NULL;
2764 }
2765
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002766 kfree(ioc->ChainToChain);
2767 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002768
2769 if (ioc->HostPageBuffer != NULL) {
2770 if((ret = mpt_host_page_access_control(ioc,
2771 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002772 printk(MYIOC_s_ERR_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302773 ": %s: host page buffers free failed (%d)!\n",
2774 ioc->name, __func__, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002775 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302776 dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2777 "HostPageBuffer free @ %p, sz=%d bytes\n",
2778 ioc->name, ioc->HostPageBuffer,
2779 ioc->HostPageBuffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002780 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002781 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002782 ioc->HostPageBuffer = NULL;
2783 ioc->HostPageBuffer_sz = 0;
2784 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2785 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786
Kashyap, Desai2f187862009-05-29 16:52:37 +05302787 pci_set_drvdata(ioc->pcidev, NULL);
2788}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002790/**
2791 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 * @ioc: Pointer to MPT adapter structure
2793 *
2794 * This routine unregisters h/w resources and frees all alloc'd memory
2795 * associated with a MPT adapter structure.
2796 */
2797static void
2798mpt_adapter_dispose(MPT_ADAPTER *ioc)
2799{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002800 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002802 if (ioc == NULL)
2803 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002805 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002807 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002809 if (ioc->pci_irq != -1) {
2810 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302811 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002812 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002813 ioc->pci_irq = -1;
2814 }
2815
2816 if (ioc->memmap != NULL) {
2817 iounmap(ioc->memmap);
2818 ioc->memmap = NULL;
2819 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302821 pci_disable_device(ioc->pcidev);
2822 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2823
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002825 if (ioc->mtrr_reg > 0) {
2826 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002827 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002828 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829#endif
2830
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002831 /* Zap the adapter lookup ptr! */
2832 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002834 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002835 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2836 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002837
2838 if (ioc->alt_ioc)
2839 ioc->alt_ioc->alt_ioc = NULL;
2840
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002841 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842}
2843
2844/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002845/**
2846 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 * @ioc: Pointer to MPT adapter structure
2848 */
2849static void
2850MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2851{
2852 int i = 0;
2853
2854 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302855 if (ioc->prod_name)
2856 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 printk("Capabilities={");
2858
2859 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2860 printk("Initiator");
2861 i++;
2862 }
2863
2864 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2865 printk("%sTarget", i ? "," : "");
2866 i++;
2867 }
2868
2869 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2870 printk("%sLAN", i ? "," : "");
2871 i++;
2872 }
2873
2874#if 0
2875 /*
2876 * This would probably evoke more questions than it's worth
2877 */
2878 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2879 printk("%sLogBusAddr", i ? "," : "");
2880 i++;
2881 }
2882#endif
2883
2884 printk("}\n");
2885}
2886
2887/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002888/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2890 * @ioc: Pointer to MPT_ADAPTER structure
2891 * @force: Force hard KickStart of IOC
2892 * @sleepFlag: Specifies whether the process can sleep
2893 *
2894 * Returns:
2895 * 1 - DIAG reset and READY
2896 * 0 - READY initially OR soft reset and READY
2897 * -1 - Any failure on KickStart
2898 * -2 - Msg Unit Reset Failed
2899 * -3 - IO Unit Reset Failed
2900 * -4 - IOC owned by a PEER
2901 */
2902static int
2903MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2904{
2905 u32 ioc_state;
2906 int statefault = 0;
2907 int cntdn;
2908 int hard_reset_done = 0;
2909 int r;
2910 int ii;
2911 int whoinit;
2912
2913 /* Get current [raw] IOC state */
2914 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002915 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916
2917 /*
2918 * Check to see if IOC got left/stuck in doorbell handshake
2919 * grip of death. If so, hard reset the IOC.
2920 */
2921 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2922 statefault = 1;
2923 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2924 ioc->name);
2925 }
2926
2927 /* Is it already READY? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302928 if (!statefault &&
2929 ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) {
2930 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2931 "IOC is in READY state\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 return 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302933 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934
2935 /*
2936 * Check to see if IOC is in FAULT state.
2937 */
2938 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2939 statefault = 2;
2940 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002941 ioc->name);
2942 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2943 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 }
2945
2946 /*
2947 * Hmmm... Did it get left operational?
2948 */
2949 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302950 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 ioc->name));
2952
2953 /* Check WhoInit.
2954 * If PCI Peer, exit.
2955 * Else, if no fault conditions are present, issue a MessageUnitReset
2956 * Else, fall through to KickStart case
2957 */
2958 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002959 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2960 "whoinit 0x%x statefault %d force %d\n",
2961 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 if (whoinit == MPI_WHOINIT_PCI_PEER)
2963 return -4;
2964 else {
2965 if ((statefault == 0 ) && (force == 0)) {
2966 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2967 return 0;
2968 }
2969 statefault = 3;
2970 }
2971 }
2972
2973 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2974 if (hard_reset_done < 0)
2975 return -1;
2976
2977 /*
2978 * Loop here waiting for IOC to come READY.
2979 */
2980 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002981 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982
2983 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2984 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2985 /*
2986 * BIOS or previous driver load left IOC in OP state.
2987 * Reset messaging FIFOs.
2988 */
2989 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2990 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2991 return -2;
2992 }
2993 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2994 /*
2995 * Something is wrong. Try to get IOC back
2996 * to a known state.
2997 */
2998 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2999 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
3000 return -3;
3001 }
3002 }
3003
3004 ii++; cntdn--;
3005 if (!cntdn) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303006 printk(MYIOC_s_ERR_FMT
3007 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
3008 ioc->name, ioc_state, (int)((ii+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 return -ETIME;
3010 }
3011
3012 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003013 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 } else {
3015 mdelay (1); /* 1 msec delay */
3016 }
3017
3018 }
3019
3020 if (statefault < 3) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303021 printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name,
3022 statefault == 1 ? "stuck handshake" : "IOC FAULT");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 }
3024
3025 return hard_reset_done;
3026}
3027
3028/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003029/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 * mpt_GetIocState - Get the current state of a MPT adapter.
3031 * @ioc: Pointer to MPT_ADAPTER structure
3032 * @cooked: Request raw or cooked IOC state
3033 *
3034 * Returns all IOC Doorbell register bits if cooked==0, else just the
3035 * Doorbell bits in MPI_IOC_STATE_MASK.
3036 */
3037u32
3038mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
3039{
3040 u32 s, sc;
3041
3042 /* Get! */
3043 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 sc = s & MPI_IOC_STATE_MASK;
3045
3046 /* Save! */
3047 ioc->last_state = sc;
3048
3049 return cooked ? sc : s;
3050}
3051
3052/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003053/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 * GetIocFacts - Send IOCFacts request to MPT adapter.
3055 * @ioc: Pointer to MPT_ADAPTER structure
3056 * @sleepFlag: Specifies whether the process can sleep
3057 * @reason: If recovery, only update facts.
3058 *
3059 * Returns 0 for success, non-zero for failure.
3060 */
3061static int
3062GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
3063{
3064 IOCFacts_t get_facts;
3065 IOCFactsReply_t *facts;
3066 int r;
3067 int req_sz;
3068 int reply_sz;
3069 int sz;
3070 u32 status, vv;
3071 u8 shiftFactor=1;
3072
3073 /* IOC *must* NOT be in RESET state! */
3074 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303075 printk(KERN_ERR MYNAM
3076 ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
3077 ioc->name, ioc->last_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 return -44;
3079 }
3080
3081 facts = &ioc->facts;
3082
3083 /* Destination (reply area)... */
3084 reply_sz = sizeof(*facts);
3085 memset(facts, 0, reply_sz);
3086
3087 /* Request area (get_facts on the stack right now!) */
3088 req_sz = sizeof(get_facts);
3089 memset(&get_facts, 0, req_sz);
3090
3091 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
3092 /* Assert: All other get_facts fields are zero! */
3093
Prakash, Sathya436ace72007-07-24 15:42:08 +05303094 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003095 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 ioc->name, req_sz, reply_sz));
3097
3098 /* No non-zero fields in the get_facts request are greater than
3099 * 1 byte in size, so we can just fire it off as is.
3100 */
3101 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3102 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3103 if (r != 0)
3104 return r;
3105
3106 /*
3107 * Now byte swap (GRRR) the necessary fields before any further
3108 * inspection of reply contents.
3109 *
3110 * But need to do some sanity checks on MsgLength (byte) field
3111 * to make sure we don't zero IOC's req_sz!
3112 */
3113 /* Did we get a valid reply? */
3114 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3115 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3116 /*
3117 * If not been here, done that, save off first WhoInit value
3118 */
3119 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3120 ioc->FirstWhoInit = facts->WhoInit;
3121 }
3122
3123 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3124 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3125 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3126 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3127 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003128 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 /* CHECKME! IOCStatus, IOCLogInfo */
3130
3131 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3132 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3133
3134 /*
3135 * FC f/w version changed between 1.1 and 1.2
3136 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3137 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3138 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303139 if (facts->MsgVersion < MPI_VERSION_01_02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 /*
3141 * Handle old FC f/w style, convert to new...
3142 */
3143 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3144 facts->FWVersion.Word =
3145 ((oldv<<12) & 0xFF000000) |
3146 ((oldv<<8) & 0x000FFF00);
3147 } else
3148 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3149
3150 facts->ProductID = le16_to_cpu(facts->ProductID);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303151
Eric Mooreb506ade2007-01-29 09:45:37 -07003152 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3153 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3154 ioc->ir_firmware = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303155
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 facts->CurrentHostMfaHighAddr =
3157 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3158 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3159 facts->CurrentSenseBufferHighAddr =
3160 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3161 facts->CurReplyFrameSize =
3162 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003163 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164
3165 /*
3166 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3167 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3168 * to 14 in MPI-1.01.0x.
3169 */
3170 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
Kashyap, Desai2f187862009-05-29 16:52:37 +05303171 facts->MsgVersion > MPI_VERSION_01_00) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3173 }
3174
Rasmus Villemoesf6e495a2014-07-01 14:56:20 +02003175 facts->FWImageSize = ALIGN(facts->FWImageSize, 4);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003176
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 if (!facts->RequestFrameSize) {
3178 /* Something is wrong! */
3179 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3180 ioc->name);
3181 return -55;
3182 }
3183
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003184 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 vv = ((63 / (sz * 4)) + 1) & 0x03;
3186 ioc->NB_for_64_byte_frame = vv;
3187 while ( sz )
3188 {
3189 shiftFactor++;
3190 sz = sz >> 1;
3191 }
3192 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303193 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003194 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3195 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003196
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3198 /*
3199 * Set values for this IOC's request & reply frame sizes,
3200 * and request & reply queue depths...
3201 */
3202 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3203 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3204 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3205 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3206
Prakash, Sathya436ace72007-07-24 15:42:08 +05303207 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303209 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 ioc->name, ioc->req_sz, ioc->req_depth));
3211
3212 /* Get port facts! */
3213 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3214 return r;
3215 }
3216 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003217 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3219 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3220 RequestFrameSize)/sizeof(u32)));
3221 return -66;
3222 }
3223
3224 return 0;
3225}
3226
3227/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003228/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 * GetPortFacts - Send PortFacts request to MPT adapter.
3230 * @ioc: Pointer to MPT_ADAPTER structure
3231 * @portnum: Port number
3232 * @sleepFlag: Specifies whether the process can sleep
3233 *
3234 * Returns 0 for success, non-zero for failure.
3235 */
3236static int
3237GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3238{
3239 PortFacts_t get_pfacts;
3240 PortFactsReply_t *pfacts;
3241 int ii;
3242 int req_sz;
3243 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003244 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245
3246 /* IOC *must* NOT be in RESET state! */
3247 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003248 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3249 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 return -4;
3251 }
3252
3253 pfacts = &ioc->pfacts[portnum];
3254
3255 /* Destination (reply area)... */
3256 reply_sz = sizeof(*pfacts);
3257 memset(pfacts, 0, reply_sz);
3258
3259 /* Request area (get_pfacts on the stack right now!) */
3260 req_sz = sizeof(get_pfacts);
3261 memset(&get_pfacts, 0, req_sz);
3262
3263 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3264 get_pfacts.PortNumber = portnum;
3265 /* Assert: All other get_pfacts fields are zero! */
3266
Prakash, Sathya436ace72007-07-24 15:42:08 +05303267 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 ioc->name, portnum));
3269
3270 /* No non-zero fields in the get_pfacts request are greater than
3271 * 1 byte in size, so we can just fire it off as is.
3272 */
3273 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3274 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3275 if (ii != 0)
3276 return ii;
3277
3278 /* Did we get a valid reply? */
3279
3280 /* Now byte swap the necessary fields in the response. */
3281 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3282 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3283 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3284 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3285 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3286 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3287 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3288 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3289 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3290
Eric Moore793955f2007-01-29 09:42:20 -07003291 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3292 pfacts->MaxDevices;
3293 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3294 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3295
3296 /*
3297 * Place all the devices on channels
3298 *
3299 * (for debuging)
3300 */
3301 if (mpt_channel_mapping) {
3302 ioc->devices_per_bus = 1;
3303 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3304 }
3305
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306 return 0;
3307}
3308
3309/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003310/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 * SendIocInit - Send IOCInit request to MPT adapter.
3312 * @ioc: Pointer to MPT_ADAPTER structure
3313 * @sleepFlag: Specifies whether the process can sleep
3314 *
3315 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3316 *
3317 * Returns 0 for success, non-zero for failure.
3318 */
3319static int
3320SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3321{
3322 IOCInit_t ioc_init;
3323 MPIDefaultReply_t init_reply;
3324 u32 state;
3325 int r;
3326 int count;
3327 int cntdn;
3328
3329 memset(&ioc_init, 0, sizeof(ioc_init));
3330 memset(&init_reply, 0, sizeof(init_reply));
3331
3332 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3333 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3334
3335 /* If we are in a recovery mode and we uploaded the FW image,
3336 * then this pointer is not NULL. Skip the upload a second time.
3337 * Set this flag if cached_fw set for either IOC.
3338 */
3339 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3340 ioc->upload_fw = 1;
3341 else
3342 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303343 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3345
Eric Moore793955f2007-01-29 09:42:20 -07003346 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3347 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303348
Prakash, Sathya436ace72007-07-24 15:42:08 +05303349 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003350 ioc->name, ioc->facts.MsgVersion));
3351 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3352 // set MsgVersion and HeaderVersion host driver was built with
3353 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3354 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003356 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3357 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3358 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3359 return -99;
3360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3362
Kashyap, Desai2f187862009-05-29 16:52:37 +05303363 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 /* Save the upper 32-bits of the request
3365 * (reply) and sense buffers.
3366 */
3367 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3368 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3369 } else {
3370 /* Force 32-bit addressing */
3371 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3372 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3373 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003374
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3376 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003377 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3378 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379
Prakash, Sathya436ace72007-07-24 15:42:08 +05303380 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 ioc->name, &ioc_init));
3382
3383 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3384 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003385 if (r != 0) {
3386 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389
3390 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003391 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 */
3393
Prakash, Sathya436ace72007-07-24 15:42:08 +05303394 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003396
3397 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3398 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401
3402 /* YIKES! SUPER IMPORTANT!!!
3403 * Poll IocState until _OPERATIONAL while IOC is doing
3404 * LoopInit and TargetDiscovery!
3405 */
3406 count = 0;
3407 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3408 state = mpt_GetIocState(ioc, 1);
3409 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3410 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003411 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 } else {
3413 mdelay(1);
3414 }
3415
3416 if (!cntdn) {
3417 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3418 ioc->name, (int)((count+5)/HZ));
3419 return -9;
3420 }
3421
3422 state = mpt_GetIocState(ioc, 1);
3423 count++;
3424 }
Eric Moore29dd3602007-09-14 18:46:51 -06003425 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 ioc->name, count));
3427
Eric Mooreba856d32006-07-11 17:34:01 -06003428 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 return r;
3430}
3431
3432/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003433/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 * SendPortEnable - Send PortEnable request to MPT adapter port.
3435 * @ioc: Pointer to MPT_ADAPTER structure
3436 * @portnum: Port number to enable
3437 * @sleepFlag: Specifies whether the process can sleep
3438 *
3439 * Send PortEnable to bring IOC to OPERATIONAL state.
3440 *
3441 * Returns 0 for success, non-zero for failure.
3442 */
3443static int
3444SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3445{
3446 PortEnable_t port_enable;
3447 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003448 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 int req_sz;
3450 int reply_sz;
3451
3452 /* Destination... */
3453 reply_sz = sizeof(MPIDefaultReply_t);
3454 memset(&reply_buf, 0, reply_sz);
3455
3456 req_sz = sizeof(PortEnable_t);
3457 memset(&port_enable, 0, req_sz);
3458
3459 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3460 port_enable.PortNumber = portnum;
3461/* port_enable.ChainOffset = 0; */
3462/* port_enable.MsgFlags = 0; */
3463/* port_enable.MsgContext = 0; */
3464
Prakash, Sathya436ace72007-07-24 15:42:08 +05303465 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 ioc->name, portnum, &port_enable));
3467
3468 /* RAID FW may take a long time to enable
3469 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003470 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003471 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3472 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3473 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003474 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003475 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3476 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3477 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003479 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480}
3481
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003482/**
3483 * mpt_alloc_fw_memory - allocate firmware memory
3484 * @ioc: Pointer to MPT_ADAPTER structure
3485 * @size: total FW bytes
3486 *
3487 * If memory has already been allocated, the same (cached) value
3488 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303489 *
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003490 * Return 0 if successful, or non-zero for failure
Prakash, Sathya984621b2008-01-11 14:42:17 +05303491 **/
3492int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3494{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303495 int rc;
3496
3497 if (ioc->cached_fw) {
3498 rc = 0; /* use already allocated memory */
3499 goto out;
3500 }
3501 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3503 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303504 rc = 0;
3505 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303507 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3508 if (!ioc->cached_fw) {
3509 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3510 ioc->name);
3511 rc = -1;
3512 } else {
3513 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3514 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3515 ioc->alloc_total += size;
3516 rc = 0;
3517 }
3518 out:
3519 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303521
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003522/**
3523 * mpt_free_fw_memory - free firmware memory
3524 * @ioc: Pointer to MPT_ADAPTER structure
3525 *
3526 * If alt_img is NULL, delete from ioc structure.
3527 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303528 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529void
3530mpt_free_fw_memory(MPT_ADAPTER *ioc)
3531{
3532 int sz;
3533
Prakash, Sathya984621b2008-01-11 14:42:17 +05303534 if (!ioc->cached_fw)
3535 return;
3536
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303538 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3539 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003540 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303541 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543}
3544
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003546/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3548 * @ioc: Pointer to MPT_ADAPTER structure
3549 * @sleepFlag: Specifies whether the process can sleep
3550 *
3551 * Returns 0 for success, >0 for handshake failure
3552 * <0 for fw upload failure.
3553 *
3554 * Remark: If bound IOC and a successful FWUpload was performed
3555 * on the bound IOC, the second image is discarded
3556 * and memory is free'd. Both channels must upload to prevent
3557 * IOC from running in degraded mode.
3558 */
3559static int
3560mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3561{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 u8 reply[sizeof(FWUploadReply_t)];
3563 FWUpload_t *prequest;
3564 FWUploadReply_t *preply;
3565 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566 u32 flagsLength;
3567 int ii, sz, reply_sz;
3568 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303569 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 /* If the image size is 0, we are done.
3571 */
3572 if ((sz = ioc->facts.FWImageSize) == 0)
3573 return 0;
3574
Prakash, Sathya984621b2008-01-11 14:42:17 +05303575 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3576 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577
Eric Moore29dd3602007-09-14 18:46:51 -06003578 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3579 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003580
Eric Moorebc6e0892007-09-29 10:16:28 -06003581 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3582 kzalloc(ioc->req_sz, GFP_KERNEL);
3583 if (!prequest) {
3584 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3585 "while allocating memory \n", ioc->name));
3586 mpt_free_fw_memory(ioc);
3587 return -ENOMEM;
3588 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589
Eric Moorebc6e0892007-09-29 10:16:28 -06003590 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591
3592 reply_sz = sizeof(reply);
3593 memset(preply, 0, reply_sz);
3594
3595 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3596 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3597
3598 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3599 ptcsge->DetailsLength = 12;
3600 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3601 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003602 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303605 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3606 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3607 ioc->SGE_size;
3608 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3609 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3610 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003611 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303613 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3614 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615
Kashyap, Desai2f187862009-05-29 16:52:37 +05303616 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
3617 "rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618
3619 cmdStatus = -EFAULT;
3620 if (ii == 0) {
3621 /* Handshake transfer was complete and successful.
3622 * Check the Reply Frame.
3623 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303624 int status;
3625 status = le16_to_cpu(preply->IOCStatus) &
3626 MPI_IOCSTATUS_MASK;
3627 if (status == MPI_IOCSTATUS_SUCCESS &&
3628 ioc->facts.FWImageSize ==
3629 le32_to_cpu(preply->ActualImageSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 cmdStatus = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303632 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 ioc->name, cmdStatus));
3634
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003635
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 if (cmdStatus) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303637 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
3638 "freeing image \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 mpt_free_fw_memory(ioc);
3640 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003641 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642
3643 return cmdStatus;
3644}
3645
3646/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003647/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 * mpt_downloadboot - DownloadBoot code
3649 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003650 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 * @sleepFlag: Specifies whether the process can sleep
3652 *
3653 * FwDownloadBoot requires Programmed IO access.
3654 *
3655 * Returns 0 for success
3656 * -1 FW Image size is 0
3657 * -2 No valid cached_fw Pointer
3658 * <0 for fw upload failure.
3659 */
3660static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003661mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 MpiExtImageHeader_t *pExtImage;
3664 u32 fwSize;
3665 u32 diag0val;
3666 int count;
3667 u32 *ptrFw;
3668 u32 diagRwData;
3669 u32 nextImage;
3670 u32 load_addr;
3671 u32 ioc_state=0;
3672
Prakash, Sathya436ace72007-07-24 15:42:08 +05303673 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003674 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003675
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3677 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3678 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3679 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3680 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3681 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3682
3683 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3684
3685 /* wait 1 msec */
3686 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003687 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 } else {
3689 mdelay (1);
3690 }
3691
3692 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3693 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3694
3695 for (count = 0; count < 30; count ++) {
3696 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3697 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303698 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699 ioc->name, count));
3700 break;
3701 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003702 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003704 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003706 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 }
3708 }
3709
3710 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303711 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003712 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 ioc->name, diag0val));
3714 return -3;
3715 }
3716
3717 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3718 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3719 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3720 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3721 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3722 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3723
3724 /* Set the DiagRwEn and Disable ARM bits */
3725 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3726
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727 fwSize = (pFwHeader->ImageSize + 3)/4;
3728 ptrFw = (u32 *) pFwHeader;
3729
3730 /* Write the LoadStartAddress to the DiagRw Address Register
3731 * using Programmed IO
3732 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003733 if (ioc->errata_flag_1064)
3734 pci_enable_io_access(ioc->pcidev);
3735
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303737 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738 ioc->name, pFwHeader->LoadStartAddress));
3739
Prakash, Sathya436ace72007-07-24 15:42:08 +05303740 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741 ioc->name, fwSize*4, ptrFw));
3742 while (fwSize--) {
3743 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3744 }
3745
3746 nextImage = pFwHeader->NextImageHeaderOffset;
3747 while (nextImage) {
3748 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3749
3750 load_addr = pExtImage->LoadStartAddress;
3751
3752 fwSize = (pExtImage->ImageSize + 3) >> 2;
3753 ptrFw = (u32 *)pExtImage;
3754
Prakash, Sathya436ace72007-07-24 15:42:08 +05303755 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 +02003756 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3758
3759 while (fwSize--) {
3760 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3761 }
3762 nextImage = pExtImage->NextImageHeaderOffset;
3763 }
3764
3765 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303766 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3768
3769 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303770 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3772
3773 /* Clear the internal flash bad bit - autoincrementing register,
3774 * so must do two writes.
3775 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003776 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003777 /*
3778 * 1030 and 1035 H/W errata, workaround to access
3779 * the ClearFlashBadSignatureBit
3780 */
3781 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3782 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3783 diagRwData |= 0x40000000;
3784 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3785 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3786
3787 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3788 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3789 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3790 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3791
3792 /* wait 1 msec */
3793 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003794 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003795 } else {
3796 mdelay (1);
3797 }
3798 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003800 if (ioc->errata_flag_1064)
3801 pci_disable_io_access(ioc->pcidev);
3802
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303804 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003805 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003807 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303808 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809 ioc->name, diag0val));
3810 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3811
3812 /* Write 0xFF to reset the sequencer */
3813 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3814
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003815 if (ioc->bus_type == SAS) {
3816 ioc_state = mpt_GetIocState(ioc, 0);
3817 if ( (GetIocFacts(ioc, sleepFlag,
3818 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303819 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003820 ioc->name, ioc_state));
3821 return -EFAULT;
3822 }
3823 }
3824
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825 for (count=0; count<HZ*20; count++) {
3826 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303827 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3828 "downloadboot successful! (count=%d) IocState=%x\n",
3829 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003830 if (ioc->bus_type == SAS) {
3831 return 0;
3832 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303834 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3835 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 ioc->name));
3837 return -EFAULT;
3838 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303839 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3840 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 ioc->name));
3842 return 0;
3843 }
3844 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003845 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846 } else {
3847 mdelay (10);
3848 }
3849 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303850 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3851 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 return -EFAULT;
3853}
3854
3855/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003856/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 * KickStart - Perform hard reset of MPT adapter.
3858 * @ioc: Pointer to MPT_ADAPTER structure
3859 * @force: Force hard reset
3860 * @sleepFlag: Specifies whether the process can sleep
3861 *
3862 * This routine places MPT adapter in diagnostic mode via the
3863 * WriteSequence register, and then performs a hard reset of adapter
3864 * via the Diagnostic register.
3865 *
3866 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3867 * or NO_SLEEP (interrupt thread, use mdelay)
3868 * force - 1 if doorbell active, board fault state
3869 * board operational, IOC_RECOVERY or
3870 * IOC_BRINGUP and there is an alt_ioc.
3871 * 0 else
3872 *
3873 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003874 * 1 - hard reset, READY
3875 * 0 - no reset due to History bit, READY
3876 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 * OR reset but failed to come READY
3878 * -2 - no reset, could not enter DIAG mode
3879 * -3 - reset but bad FW bit
3880 */
3881static int
3882KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3883{
3884 int hard_reset_done = 0;
3885 u32 ioc_state=0;
3886 int cnt,cntdn;
3887
Eric Moore29dd3602007-09-14 18:46:51 -06003888 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003889 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 /* Always issue a Msg Unit Reset first. This will clear some
3891 * SCSI bus hang conditions.
3892 */
3893 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3894
3895 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003896 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 } else {
3898 mdelay (1000);
3899 }
3900 }
3901
3902 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3903 if (hard_reset_done < 0)
3904 return hard_reset_done;
3905
Prakash, Sathya436ace72007-07-24 15:42:08 +05303906 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003907 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908
3909 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3910 for (cnt=0; cnt<cntdn; cnt++) {
3911 ioc_state = mpt_GetIocState(ioc, 1);
3912 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303913 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 ioc->name, cnt));
3915 return hard_reset_done;
3916 }
3917 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003918 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919 } else {
3920 mdelay (10);
3921 }
3922 }
3923
Eric Moore29dd3602007-09-14 18:46:51 -06003924 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3925 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926 return -1;
3927}
3928
3929/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003930/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931 * mpt_diag_reset - Perform hard reset of the adapter.
3932 * @ioc: Pointer to MPT_ADAPTER structure
3933 * @ignore: Set if to honor and clear to ignore
3934 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003935 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936 * else set to NO_SLEEP (use mdelay instead)
3937 *
3938 * This routine places the adapter in diagnostic mode via the
3939 * WriteSequence register and then performs a hard reset of adapter
3940 * via the Diagnostic register. Adapter should be in ready state
3941 * upon successful completion.
3942 *
3943 * Returns: 1 hard reset successful
3944 * 0 no reset performed because reset history bit set
3945 * -2 enabling diagnostic mode failed
3946 * -3 diagnostic reset failed
3947 */
3948static int
3949mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3950{
3951 u32 diag0val;
3952 u32 doorbell;
3953 int hard_reset_done = 0;
3954 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303956 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Kashyap, Desaid1306912009-08-05 12:53:51 +05303957 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003958
Eric Moorecd2c6192007-01-29 09:47:47 -07003959 /* Clear any existing interrupts */
3960 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3961
Eric Moore87cf8982006-06-27 16:09:26 -06003962 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303963
3964 if (!ignore)
3965 return 0;
3966
Prakash, Sathya436ace72007-07-24 15:42:08 +05303967 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003968 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003969 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3970 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3971 if (sleepFlag == CAN_SLEEP)
3972 msleep(1);
3973 else
3974 mdelay(1);
3975
Kashyap, Desaid1306912009-08-05 12:53:51 +05303976 /*
3977 * Call each currently registered protocol IOC reset handler
3978 * with pre-reset indication.
3979 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3980 * MptResetHandlers[] registered yet.
3981 */
3982 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3983 if (MptResetHandlers[cb_idx])
3984 (*(MptResetHandlers[cb_idx]))(ioc,
3985 MPT_IOC_PRE_RESET);
3986 }
3987
Eric Moore87cf8982006-06-27 16:09:26 -06003988 for (count = 0; count < 60; count ++) {
3989 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3990 doorbell &= MPI_IOC_STATE_MASK;
3991
Prakash, Sathya436ace72007-07-24 15:42:08 +05303992 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003993 "looking for READY STATE: doorbell=%x"
3994 " count=%d\n",
3995 ioc->name, doorbell, count));
Kashyap, Desai2f187862009-05-29 16:52:37 +05303996
Eric Moore87cf8982006-06-27 16:09:26 -06003997 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003998 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003999 }
4000
4001 /* wait 1 sec */
4002 if (sleepFlag == CAN_SLEEP)
4003 msleep(1000);
4004 else
4005 mdelay(1000);
4006 }
4007 return -1;
4008 }
4009
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 /* Use "Diagnostic reset" method! (only thing available!) */
4011 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4012
Prakash, Sathya436ace72007-07-24 15:42:08 +05304013 if (ioc->debug_level & MPT_DEBUG) {
4014 if (ioc->alt_ioc)
4015 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4016 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304018 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019
4020 /* Do the reset if we are told to ignore the reset history
4021 * or if the reset history is 0
4022 */
4023 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
4024 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4025 /* Write magic sequence to WriteSequence register
4026 * Loop until in diagnostic mode
4027 */
4028 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4029 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4030 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4031 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4032 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4033 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4034
4035 /* wait 100 msec */
4036 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004037 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 } else {
4039 mdelay (100);
4040 }
4041
4042 count++;
4043 if (count > 20) {
4044 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4045 ioc->name, diag0val);
4046 return -2;
4047
4048 }
4049
4050 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4051
Prakash, Sathya436ace72007-07-24 15:42:08 +05304052 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053 ioc->name, diag0val));
4054 }
4055
Prakash, Sathya436ace72007-07-24 15:42:08 +05304056 if (ioc->debug_level & MPT_DEBUG) {
4057 if (ioc->alt_ioc)
4058 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4059 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304061 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062 /*
4063 * Disable the ARM (Bug fix)
4064 *
4065 */
4066 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004067 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068
4069 /*
4070 * Now hit the reset bit in the Diagnostic register
4071 * (THE BIG HAMMER!) (Clears DRWE bit).
4072 */
4073 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
4074 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304075 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076 ioc->name));
4077
4078 /*
4079 * Call each currently registered protocol IOC reset handler
4080 * with pre-reset indication.
4081 * NOTE: If we're doing _IOC_BRINGUP, there can be no
4082 * MptResetHandlers[] registered yet.
4083 */
Kashyap, Desaid1306912009-08-05 12:53:51 +05304084 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
4085 if (MptResetHandlers[cb_idx]) {
4086 mpt_signal_reset(cb_idx,
4087 ioc, MPT_IOC_PRE_RESET);
4088 if (ioc->alt_ioc) {
4089 mpt_signal_reset(cb_idx,
4090 ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091 }
4092 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004093 }
4094
Eric Moore0ccdb002006-07-11 17:33:13 -06004095 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304096 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06004097 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304098 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4099 else
4100 cached_fw = NULL;
4101 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102 /* If the DownloadBoot operation fails, the
4103 * IOC will be left unusable. This is a fatal error
4104 * case. _diag_reset will return < 0
4105 */
4106 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304107 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4109 break;
4110 }
4111
Prakash, Sathya436ace72007-07-24 15:42:08 +05304112 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304113 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114 /* wait 1 sec */
4115 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004116 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 } else {
4118 mdelay (1000);
4119 }
4120 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304121 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004122 printk(MYIOC_s_WARN_FMT
4123 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124 }
4125
4126 } else {
4127 /* Wait for FW to reload and for board
4128 * to go to the READY state.
4129 * Maximum wait is 60 seconds.
4130 * If fail, no error will check again
4131 * with calling program.
4132 */
4133 for (count = 0; count < 60; count ++) {
4134 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4135 doorbell &= MPI_IOC_STATE_MASK;
4136
Kashyap, Desai2f187862009-05-29 16:52:37 +05304137 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4138 "looking for READY STATE: doorbell=%x"
4139 " count=%d\n", ioc->name, doorbell, count));
4140
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 if (doorbell == MPI_IOC_STATE_READY) {
4142 break;
4143 }
4144
4145 /* wait 1 sec */
4146 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004147 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148 } else {
4149 mdelay (1000);
4150 }
4151 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05304152
4153 if (doorbell != MPI_IOC_STATE_READY)
4154 printk(MYIOC_s_ERR_FMT "Failed to come READY "
4155 "after reset! IocState=%x", ioc->name,
4156 doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157 }
4158 }
4159
4160 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304161 if (ioc->debug_level & MPT_DEBUG) {
4162 if (ioc->alt_ioc)
4163 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4164 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4165 ioc->name, diag0val, diag1val));
4166 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167
4168 /* Clear RESET_HISTORY bit! Place board in the
4169 * diagnostic mode to update the diag register.
4170 */
4171 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4172 count = 0;
4173 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4174 /* Write magic sequence to WriteSequence register
4175 * Loop until in diagnostic mode
4176 */
4177 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4178 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4179 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4180 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4181 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4182 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4183
4184 /* wait 100 msec */
4185 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004186 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187 } else {
4188 mdelay (100);
4189 }
4190
4191 count++;
4192 if (count > 20) {
4193 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4194 ioc->name, diag0val);
4195 break;
4196 }
4197 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4198 }
4199 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4200 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4201 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4202 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4203 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4204 ioc->name);
4205 }
4206
4207 /* Disable Diagnostic Mode
4208 */
4209 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4210
4211 /* Check FW reload status flags.
4212 */
4213 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4214 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4215 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4216 ioc->name, diag0val);
4217 return -3;
4218 }
4219
Prakash, Sathya436ace72007-07-24 15:42:08 +05304220 if (ioc->debug_level & MPT_DEBUG) {
4221 if (ioc->alt_ioc)
4222 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4223 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304225 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226
4227 /*
4228 * Reset flag that says we've enabled event notification
4229 */
4230 ioc->facts.EventState = 0;
4231
4232 if (ioc->alt_ioc)
4233 ioc->alt_ioc->facts.EventState = 0;
4234
4235 return hard_reset_done;
4236}
4237
4238/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004239/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 * SendIocReset - Send IOCReset request to MPT adapter.
4241 * @ioc: Pointer to MPT_ADAPTER structure
4242 * @reset_type: reset type, expected values are
4243 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004244 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 *
4246 * Send IOCReset request to the MPT adapter.
4247 *
4248 * Returns 0 for success, non-zero for failure.
4249 */
4250static int
4251SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4252{
4253 int r;
4254 u32 state;
4255 int cntdn, count;
4256
Prakash, Sathya436ace72007-07-24 15:42:08 +05304257 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 ioc->name, reset_type));
4259 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4260 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4261 return r;
4262
4263 /* FW ACK'd request, wait for READY state
4264 */
4265 count = 0;
4266 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4267
4268 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4269 cntdn--;
4270 count++;
4271 if (!cntdn) {
4272 if (sleepFlag != CAN_SLEEP)
4273 count *= 10;
4274
Kashyap, Desai2f187862009-05-29 16:52:37 +05304275 printk(MYIOC_s_ERR_FMT
4276 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
4277 ioc->name, state, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278 return -ETIME;
4279 }
4280
4281 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004282 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283 } else {
4284 mdelay (1); /* 1 msec delay */
4285 }
4286 }
4287
4288 /* TODO!
4289 * Cleanup all event stuff for this IOC; re-issue EventNotification
4290 * request if needed.
4291 */
4292 if (ioc->facts.Function)
4293 ioc->facts.EventState = 0;
4294
4295 return 0;
4296}
4297
4298/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004299/**
4300 * initChainBuffers - Allocate memory for and initialize chain buffers
4301 * @ioc: Pointer to MPT_ADAPTER structure
4302 *
4303 * Allocates memory for and initializes chain buffers,
4304 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 */
4306static int
4307initChainBuffers(MPT_ADAPTER *ioc)
4308{
4309 u8 *mem;
4310 int sz, ii, num_chain;
4311 int scale, num_sge, numSGE;
4312
4313 /* ReqToChain size must equal the req_depth
4314 * index = req_idx
4315 */
4316 if (ioc->ReqToChain == NULL) {
4317 sz = ioc->req_depth * sizeof(int);
4318 mem = kmalloc(sz, GFP_ATOMIC);
4319 if (mem == NULL)
4320 return -1;
4321
4322 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304323 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324 ioc->name, mem, sz));
4325 mem = kmalloc(sz, GFP_ATOMIC);
4326 if (mem == NULL)
4327 return -1;
4328
4329 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304330 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331 ioc->name, mem, sz));
4332 }
4333 for (ii = 0; ii < ioc->req_depth; ii++) {
4334 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4335 }
4336
4337 /* ChainToChain size must equal the total number
4338 * of chain buffers to be allocated.
4339 * index = chain_idx
4340 *
4341 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004342 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 *
4344 * num_sge = num sge in request frame + last chain buffer
4345 * scale = num sge per chain buffer if no chain element
4346 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304347 scale = ioc->req_sz / ioc->SGE_size;
4348 if (ioc->sg_addr_size == sizeof(u64))
4349 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304351 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304353 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304355 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304357 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4358 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304360 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 ioc->name, num_sge, numSGE));
4362
Kashyap, Desai2f187862009-05-29 16:52:37 +05304363 if (ioc->bus_type == FC) {
4364 if (numSGE > MPT_SCSI_FC_SG_DEPTH)
4365 numSGE = MPT_SCSI_FC_SG_DEPTH;
4366 } else {
4367 if (numSGE > MPT_SCSI_SG_DEPTH)
4368 numSGE = MPT_SCSI_SG_DEPTH;
4369 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370
4371 num_chain = 1;
4372 while (numSGE - num_sge > 0) {
4373 num_chain++;
4374 num_sge += (scale - 1);
4375 }
4376 num_chain++;
4377
Prakash, Sathya436ace72007-07-24 15:42:08 +05304378 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379 ioc->name, numSGE, num_sge, num_chain));
4380
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004381 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382 num_chain *= MPT_SCSI_CAN_QUEUE;
Anatolij Gustschinf1053a72009-12-12 14:52:21 +01004383 else if (ioc->bus_type == SAS)
4384 num_chain *= MPT_SAS_CAN_QUEUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385 else
4386 num_chain *= MPT_FC_CAN_QUEUE;
4387
4388 ioc->num_chain = num_chain;
4389
4390 sz = num_chain * sizeof(int);
4391 if (ioc->ChainToChain == NULL) {
4392 mem = kmalloc(sz, GFP_ATOMIC);
4393 if (mem == NULL)
4394 return -1;
4395
4396 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304397 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398 ioc->name, mem, sz));
4399 } else {
4400 mem = (u8 *) ioc->ChainToChain;
4401 }
4402 memset(mem, 0xFF, sz);
4403 return num_chain;
4404}
4405
4406/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004407/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4409 * @ioc: Pointer to MPT_ADAPTER structure
4410 *
4411 * This routine allocates memory for the MPT reply and request frame
4412 * pools (if necessary), and primes the IOC reply FIFO with
4413 * reply frames.
4414 *
4415 * Returns 0 for success, non-zero for failure.
4416 */
4417static int
4418PrimeIocFifos(MPT_ADAPTER *ioc)
4419{
4420 MPT_FRAME_HDR *mf;
4421 unsigned long flags;
4422 dma_addr_t alloc_dma;
4423 u8 *mem;
4424 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304425 u64 dma_mask;
4426
4427 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428
4429 /* Prime reply FIFO... */
4430
4431 if (ioc->reply_frames == NULL) {
4432 if ( (num_chain = initChainBuffers(ioc)) < 0)
4433 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304434 /*
4435 * 1078 errata workaround for the 36GB limitation
4436 */
4437 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
Andrew Morton8e20ce92009-06-18 16:49:17 -07004438 ioc->dma_mask > DMA_BIT_MASK(35)) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304439 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4440 && !pci_set_consistent_dma_mask(ioc->pcidev,
4441 DMA_BIT_MASK(32))) {
Andrew Morton8e20ce92009-06-18 16:49:17 -07004442 dma_mask = DMA_BIT_MASK(35);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304443 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4444 "setting 35 bit addressing for "
4445 "Request/Reply/Chain and Sense Buffers\n",
4446 ioc->name));
4447 } else {
4448 /*Reseting DMA mask to 64 bit*/
4449 pci_set_dma_mask(ioc->pcidev,
4450 DMA_BIT_MASK(64));
4451 pci_set_consistent_dma_mask(ioc->pcidev,
4452 DMA_BIT_MASK(64));
4453
4454 printk(MYIOC_s_ERR_FMT
4455 "failed setting 35 bit addressing for "
4456 "Request/Reply/Chain and Sense Buffers\n",
4457 ioc->name);
4458 return -1;
4459 }
4460 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461
4462 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304463 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304465 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 ioc->name, reply_sz, reply_sz));
4467
4468 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304469 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304471 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472 ioc->name, sz, sz));
4473 total_size += sz;
4474
4475 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304476 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304478 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479 ioc->name, sz, sz, num_chain));
4480
4481 total_size += sz;
4482 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4483 if (mem == NULL) {
4484 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4485 ioc->name);
4486 goto out_fail;
4487 }
4488
Prakash, Sathya436ace72007-07-24 15:42:08 +05304489 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4491
4492 memset(mem, 0, total_size);
4493 ioc->alloc_total += total_size;
4494 ioc->alloc = mem;
4495 ioc->alloc_dma = alloc_dma;
4496 ioc->alloc_sz = total_size;
4497 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4498 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4499
Prakash, Sathya436ace72007-07-24 15:42:08 +05304500 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004501 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4502
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 alloc_dma += reply_sz;
4504 mem += reply_sz;
4505
4506 /* Request FIFO - WE manage this! */
4507
4508 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4509 ioc->req_frames_dma = alloc_dma;
4510
Prakash, Sathya436ace72007-07-24 15:42:08 +05304511 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 ioc->name, mem, (void *)(ulong)alloc_dma));
4513
4514 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4515
4516#if defined(CONFIG_MTRR) && 0
4517 /*
4518 * Enable Write Combining MTRR for IOC's memory region.
4519 * (at least as much as we can; "size and base must be
4520 * multiples of 4 kiB"
4521 */
4522 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4523 sz,
4524 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304525 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526 ioc->name, ioc->req_frames_dma, sz));
4527#endif
4528
4529 for (i = 0; i < ioc->req_depth; i++) {
4530 alloc_dma += ioc->req_sz;
4531 mem += ioc->req_sz;
4532 }
4533
4534 ioc->ChainBuffer = mem;
4535 ioc->ChainBufferDMA = alloc_dma;
4536
Prakash, Sathya436ace72007-07-24 15:42:08 +05304537 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004538 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4539
4540 /* Initialize the free chain Q.
4541 */
4542
4543 INIT_LIST_HEAD(&ioc->FreeChainQ);
4544
4545 /* Post the chain buffers to the FreeChainQ.
4546 */
4547 mem = (u8 *)ioc->ChainBuffer;
4548 for (i=0; i < num_chain; i++) {
4549 mf = (MPT_FRAME_HDR *) mem;
4550 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4551 mem += ioc->req_sz;
4552 }
4553
4554 /* Initialize Request frames linked list
4555 */
4556 alloc_dma = ioc->req_frames_dma;
4557 mem = (u8 *) ioc->req_frames;
4558
4559 spin_lock_irqsave(&ioc->FreeQlock, flags);
4560 INIT_LIST_HEAD(&ioc->FreeQ);
4561 for (i = 0; i < ioc->req_depth; i++) {
4562 mf = (MPT_FRAME_HDR *) mem;
4563
4564 /* Queue REQUESTs *internally*! */
4565 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4566
4567 mem += ioc->req_sz;
4568 }
4569 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4570
4571 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4572 ioc->sense_buf_pool =
4573 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4574 if (ioc->sense_buf_pool == NULL) {
4575 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4576 ioc->name);
4577 goto out_fail;
4578 }
4579
4580 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4581 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304582 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4584
4585 }
4586
4587 /* Post Reply frames to FIFO
4588 */
4589 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304590 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4592
4593 for (i = 0; i < ioc->reply_depth; i++) {
4594 /* Write each address to the IOC! */
4595 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4596 alloc_dma += ioc->reply_sz;
4597 }
4598
Andrew Morton8e20ce92009-06-18 16:49:17 -07004599 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304600 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4601 ioc->dma_mask))
4602 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4603 "restoring 64 bit addressing\n", ioc->name));
4604
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605 return 0;
4606
4607out_fail:
Kashyap, Desai2f187862009-05-29 16:52:37 +05304608
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 if (ioc->alloc != NULL) {
4610 sz = ioc->alloc_sz;
4611 pci_free_consistent(ioc->pcidev,
4612 sz,
4613 ioc->alloc, ioc->alloc_dma);
4614 ioc->reply_frames = NULL;
4615 ioc->req_frames = NULL;
4616 ioc->alloc_total -= sz;
4617 }
4618 if (ioc->sense_buf_pool != NULL) {
4619 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4620 pci_free_consistent(ioc->pcidev,
4621 sz,
4622 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4623 ioc->sense_buf_pool = NULL;
4624 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304625
Andrew Morton8e20ce92009-06-18 16:49:17 -07004626 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304627 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4628 DMA_BIT_MASK(64)))
4629 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4630 "restoring 64 bit addressing\n", ioc->name));
4631
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 return -1;
4633}
4634
4635/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4636/**
4637 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4638 * from IOC via doorbell handshake method.
4639 * @ioc: Pointer to MPT_ADAPTER structure
4640 * @reqBytes: Size of the request in bytes
4641 * @req: Pointer to MPT request frame
4642 * @replyBytes: Expected size of the reply in bytes
4643 * @u16reply: Pointer to area where reply should be written
4644 * @maxwait: Max wait time for a reply (in seconds)
4645 * @sleepFlag: Specifies whether the process can sleep
4646 *
4647 * NOTES: It is the callers responsibility to byte-swap fields in the
4648 * request which are greater than 1 byte in size. It is also the
4649 * callers responsibility to byte-swap response fields which are
4650 * greater than 1 byte in size.
4651 *
4652 * Returns 0 for success, non-zero for failure.
4653 */
4654static int
4655mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004656 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657{
4658 MPIDefaultReply_t *mptReply;
4659 int failcnt = 0;
4660 int t;
4661
4662 /*
4663 * Get ready to cache a handshake reply
4664 */
4665 ioc->hs_reply_idx = 0;
4666 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4667 mptReply->MsgLength = 0;
4668
4669 /*
4670 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4671 * then tell IOC that we want to handshake a request of N words.
4672 * (WRITE u32val to Doorbell reg).
4673 */
4674 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4675 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4676 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4677 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4678
4679 /*
4680 * Wait for IOC's doorbell handshake int
4681 */
4682 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4683 failcnt++;
4684
Prakash, Sathya436ace72007-07-24 15:42:08 +05304685 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4687
4688 /* Read doorbell and check for active bit */
4689 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4690 return -1;
4691
4692 /*
4693 * Clear doorbell int (WRITE 0 to IntStatus reg),
4694 * then wait for IOC to ACKnowledge that it's ready for
4695 * our handshake request.
4696 */
4697 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4698 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4699 failcnt++;
4700
4701 if (!failcnt) {
4702 int ii;
4703 u8 *req_as_bytes = (u8 *) req;
4704
4705 /*
4706 * Stuff request words via doorbell handshake,
4707 * with ACK from IOC for each.
4708 */
4709 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4710 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4711 (req_as_bytes[(ii*4) + 1] << 8) |
4712 (req_as_bytes[(ii*4) + 2] << 16) |
4713 (req_as_bytes[(ii*4) + 3] << 24));
4714
4715 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4716 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4717 failcnt++;
4718 }
4719
Prakash, Sathya436ace72007-07-24 15:42:08 +05304720 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004721 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722
Prakash, Sathya436ace72007-07-24 15:42:08 +05304723 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4725
4726 /*
4727 * Wait for completion of doorbell handshake reply from the IOC
4728 */
4729 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4730 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004731
Prakash, Sathya436ace72007-07-24 15:42:08 +05304732 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4734
4735 /*
4736 * Copy out the cached reply...
4737 */
4738 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4739 u16reply[ii] = ioc->hs_reply[ii];
4740 } else {
4741 return -99;
4742 }
4743
4744 return -failcnt;
4745}
4746
4747/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004748/**
4749 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750 * @ioc: Pointer to MPT_ADAPTER structure
4751 * @howlong: How long to wait (in seconds)
4752 * @sleepFlag: Specifies whether the process can sleep
4753 *
4754 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004755 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4756 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 *
4758 * Returns a negative value on failure, else wait loop count.
4759 */
4760static int
4761WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4762{
4763 int cntdn;
4764 int count = 0;
4765 u32 intstat=0;
4766
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004767 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768
4769 if (sleepFlag == CAN_SLEEP) {
4770 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004771 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4773 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4774 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 count++;
4776 }
4777 } else {
4778 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004779 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4781 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4782 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783 count++;
4784 }
4785 }
4786
4787 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304788 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 ioc->name, count));
4790 return count;
4791 }
4792
4793 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4794 ioc->name, count, intstat);
4795 return -1;
4796}
4797
4798/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004799/**
4800 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801 * @ioc: Pointer to MPT_ADAPTER structure
4802 * @howlong: How long to wait (in seconds)
4803 * @sleepFlag: Specifies whether the process can sleep
4804 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004805 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4806 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 *
4808 * Returns a negative value on failure, else wait loop count.
4809 */
4810static int
4811WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4812{
4813 int cntdn;
4814 int count = 0;
4815 u32 intstat=0;
4816
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004817 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 if (sleepFlag == CAN_SLEEP) {
4819 while (--cntdn) {
4820 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4821 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4822 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004823 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824 count++;
4825 }
4826 } else {
4827 while (--cntdn) {
4828 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4829 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4830 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004831 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832 count++;
4833 }
4834 }
4835
4836 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304837 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838 ioc->name, count, howlong));
4839 return count;
4840 }
4841
4842 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4843 ioc->name, count, intstat);
4844 return -1;
4845}
4846
4847/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004848/**
4849 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 * @ioc: Pointer to MPT_ADAPTER structure
4851 * @howlong: How long to wait (in seconds)
4852 * @sleepFlag: Specifies whether the process can sleep
4853 *
4854 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4855 * Reply is cached to IOC private area large enough to hold a maximum
4856 * of 128 bytes of reply data.
4857 *
4858 * Returns a negative value on failure, else size of reply in WORDS.
4859 */
4860static int
4861WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4862{
4863 int u16cnt = 0;
4864 int failcnt = 0;
4865 int t;
4866 u16 *hs_reply = ioc->hs_reply;
4867 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4868 u16 hword;
4869
4870 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4871
4872 /*
4873 * Get first two u16's so we can look at IOC's intended reply MsgLength
4874 */
4875 u16cnt=0;
4876 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4877 failcnt++;
4878 } else {
4879 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4880 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4881 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4882 failcnt++;
4883 else {
4884 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4885 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4886 }
4887 }
4888
Prakash, Sathya436ace72007-07-24 15:42:08 +05304889 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004890 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4892
4893 /*
4894 * If no error (and IOC said MsgLength is > 0), piece together
4895 * reply 16 bits at a time.
4896 */
4897 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4898 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4899 failcnt++;
4900 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4901 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004902 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903 hs_reply[u16cnt] = hword;
4904 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4905 }
4906
4907 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4908 failcnt++;
4909 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4910
4911 if (failcnt) {
4912 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4913 ioc->name);
4914 return -failcnt;
4915 }
4916#if 0
4917 else if (u16cnt != (2 * mptReply->MsgLength)) {
4918 return -101;
4919 }
4920 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4921 return -102;
4922 }
4923#endif
4924
Prakash, Sathya436ace72007-07-24 15:42:08 +05304925 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004926 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927
Prakash, Sathya436ace72007-07-24 15:42:08 +05304928 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004929 ioc->name, t, u16cnt/2));
4930 return u16cnt/2;
4931}
4932
4933/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004934/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935 * GetLanConfigPages - Fetch LANConfig pages.
4936 * @ioc: Pointer to MPT_ADAPTER structure
4937 *
4938 * Return: 0 for success
4939 * -ENOMEM if no memory available
4940 * -EPERM if not allowed due to ISR context
4941 * -EAGAIN if no msg frames currently available
4942 * -EFAULT for non-successful reply or no reply (timeout)
4943 */
4944static int
4945GetLanConfigPages(MPT_ADAPTER *ioc)
4946{
4947 ConfigPageHeader_t hdr;
4948 CONFIGPARMS cfg;
4949 LANPage0_t *ppage0_alloc;
4950 dma_addr_t page0_dma;
4951 LANPage1_t *ppage1_alloc;
4952 dma_addr_t page1_dma;
4953 int rc = 0;
4954 int data_sz;
4955 int copy_sz;
4956
4957 /* Get LAN Page 0 header */
4958 hdr.PageVersion = 0;
4959 hdr.PageLength = 0;
4960 hdr.PageNumber = 0;
4961 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004962 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963 cfg.physAddr = -1;
4964 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4965 cfg.dir = 0;
4966 cfg.pageAddr = 0;
4967 cfg.timeout = 0;
4968
4969 if ((rc = mpt_config(ioc, &cfg)) != 0)
4970 return rc;
4971
4972 if (hdr.PageLength > 0) {
4973 data_sz = hdr.PageLength * 4;
4974 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4975 rc = -ENOMEM;
4976 if (ppage0_alloc) {
4977 memset((u8 *)ppage0_alloc, 0, data_sz);
4978 cfg.physAddr = page0_dma;
4979 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4980
4981 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4982 /* save the data */
4983 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4984 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4985
4986 }
4987
4988 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4989
4990 /* FIXME!
4991 * Normalize endianness of structure data,
4992 * by byte-swapping all > 1 byte fields!
4993 */
4994
4995 }
4996
4997 if (rc)
4998 return rc;
4999 }
5000
5001 /* Get LAN Page 1 header */
5002 hdr.PageVersion = 0;
5003 hdr.PageLength = 0;
5004 hdr.PageNumber = 1;
5005 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005006 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005007 cfg.physAddr = -1;
5008 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5009 cfg.dir = 0;
5010 cfg.pageAddr = 0;
5011
5012 if ((rc = mpt_config(ioc, &cfg)) != 0)
5013 return rc;
5014
5015 if (hdr.PageLength == 0)
5016 return 0;
5017
5018 data_sz = hdr.PageLength * 4;
5019 rc = -ENOMEM;
5020 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
5021 if (ppage1_alloc) {
5022 memset((u8 *)ppage1_alloc, 0, data_sz);
5023 cfg.physAddr = page1_dma;
5024 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5025
5026 if ((rc = mpt_config(ioc, &cfg)) == 0) {
5027 /* save the data */
5028 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
5029 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
5030 }
5031
5032 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
5033
5034 /* FIXME!
5035 * Normalize endianness of structure data,
5036 * by byte-swapping all > 1 byte fields!
5037 */
5038
5039 }
5040
5041 return rc;
5042}
5043
5044/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005045/**
5046 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005047 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005048 * @persist_opcode: see below
5049 *
5050 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
5051 * devices not currently present.
5052 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
5053 *
5054 * NOTE: Don't use not this function during interrupt time.
5055 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005056 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005057 */
5058
5059/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5060int
5061mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
5062{
5063 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
5064 SasIoUnitControlReply_t *sasIoUnitCntrReply;
5065 MPT_FRAME_HDR *mf = NULL;
5066 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305067 int ret = 0;
5068 unsigned long timeleft;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005069
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305070 mutex_lock(&ioc->mptbase_cmds.mutex);
5071
5072 /* init the internal cmd struct */
5073 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
5074 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005075
5076 /* insure garbage is not sent to fw */
5077 switch(persist_opcode) {
5078
5079 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
5080 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
5081 break;
5082
5083 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305084 ret = -1;
5085 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005086 }
5087
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305088 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
5089 __func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005090
5091 /* Get a MF for this command.
5092 */
5093 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305094 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
5095 ret = -1;
5096 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005097 }
5098
5099 mpi_hdr = (MPIHeader_t *) mf;
5100 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
5101 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
5102 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
5103 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
5104 sasIoUnitCntrReq->Operation = persist_opcode;
5105
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005106 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305107 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
5108 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
5109 ret = -ETIME;
5110 printk(KERN_DEBUG "%s: failed\n", __func__);
5111 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
5112 goto out;
5113 if (!timeleft) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09005114 printk(MYIOC_s_WARN_FMT
5115 "Issuing Reset from %s!!, doorbell=0x%08x\n",
5116 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05305117 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305118 mpt_free_msg_frame(ioc, mf);
5119 }
5120 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005121 }
5122
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305123 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
5124 ret = -1;
5125 goto out;
5126 }
5127
5128 sasIoUnitCntrReply =
5129 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5130 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5131 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5132 __func__, sasIoUnitCntrReply->IOCStatus,
5133 sasIoUnitCntrReply->IOCLogInfo);
5134 printk(KERN_DEBUG "%s: failed\n", __func__);
5135 ret = -1;
5136 } else
5137 printk(KERN_DEBUG "%s: success\n", __func__);
5138 out:
5139
5140 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5141 mutex_unlock(&ioc->mptbase_cmds.mutex);
5142 return ret;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005143}
5144
5145/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005146
5147static void
5148mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5149 MpiEventDataRaid_t * pRaidEventData)
5150{
5151 int volume;
5152 int reason;
5153 int disk;
5154 int status;
5155 int flags;
5156 int state;
5157
5158 volume = pRaidEventData->VolumeID;
5159 reason = pRaidEventData->ReasonCode;
5160 disk = pRaidEventData->PhysDiskNum;
5161 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5162 flags = (status >> 0) & 0xff;
5163 state = (status >> 8) & 0xff;
5164
5165 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5166 return;
5167 }
5168
5169 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5170 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5171 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005172 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5173 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005174 } else {
5175 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5176 ioc->name, volume);
5177 }
5178
5179 switch(reason) {
5180 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5181 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5182 ioc->name);
5183 break;
5184
5185 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5186
5187 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5188 ioc->name);
5189 break;
5190
5191 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5192 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5193 ioc->name);
5194 break;
5195
5196 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5197 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5198 ioc->name,
5199 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5200 ? "optimal"
5201 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5202 ? "degraded"
5203 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5204 ? "failed"
5205 : "state unknown",
5206 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5207 ? ", enabled" : "",
5208 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5209 ? ", quiesced" : "",
5210 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5211 ? ", resync in progress" : "" );
5212 break;
5213
5214 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5215 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5216 ioc->name, disk);
5217 break;
5218
5219 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5220 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5221 ioc->name);
5222 break;
5223
5224 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5225 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5226 ioc->name);
5227 break;
5228
5229 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5230 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5231 ioc->name);
5232 break;
5233
5234 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5235 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5236 ioc->name,
5237 state == MPI_PHYSDISK0_STATUS_ONLINE
5238 ? "online"
5239 : state == MPI_PHYSDISK0_STATUS_MISSING
5240 ? "missing"
5241 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5242 ? "not compatible"
5243 : state == MPI_PHYSDISK0_STATUS_FAILED
5244 ? "failed"
5245 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5246 ? "initializing"
5247 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5248 ? "offline requested"
5249 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5250 ? "failed requested"
5251 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5252 ? "offline"
5253 : "state unknown",
5254 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5255 ? ", out of sync" : "",
5256 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5257 ? ", quiesced" : "" );
5258 break;
5259
5260 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5261 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5262 ioc->name, disk);
5263 break;
5264
5265 case MPI_EVENT_RAID_RC_SMART_DATA:
5266 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5267 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5268 break;
5269
5270 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5271 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5272 ioc->name, disk);
5273 break;
5274 }
5275}
5276
5277/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005278/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5280 * @ioc: Pointer to MPT_ADAPTER structure
5281 *
5282 * Returns: 0 for success
5283 * -ENOMEM if no memory available
5284 * -EPERM if not allowed due to ISR context
5285 * -EAGAIN if no msg frames currently available
5286 * -EFAULT for non-successful reply or no reply (timeout)
5287 */
5288static int
5289GetIoUnitPage2(MPT_ADAPTER *ioc)
5290{
5291 ConfigPageHeader_t hdr;
5292 CONFIGPARMS cfg;
5293 IOUnitPage2_t *ppage_alloc;
5294 dma_addr_t page_dma;
5295 int data_sz;
5296 int rc;
5297
5298 /* Get the page header */
5299 hdr.PageVersion = 0;
5300 hdr.PageLength = 0;
5301 hdr.PageNumber = 2;
5302 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005303 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005304 cfg.physAddr = -1;
5305 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5306 cfg.dir = 0;
5307 cfg.pageAddr = 0;
5308 cfg.timeout = 0;
5309
5310 if ((rc = mpt_config(ioc, &cfg)) != 0)
5311 return rc;
5312
5313 if (hdr.PageLength == 0)
5314 return 0;
5315
5316 /* Read the config page */
5317 data_sz = hdr.PageLength * 4;
5318 rc = -ENOMEM;
5319 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5320 if (ppage_alloc) {
5321 memset((u8 *)ppage_alloc, 0, data_sz);
5322 cfg.physAddr = page_dma;
5323 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5324
5325 /* If Good, save data */
5326 if ((rc = mpt_config(ioc, &cfg)) == 0)
5327 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5328
5329 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5330 }
5331
5332 return rc;
5333}
5334
5335/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005336/**
5337 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338 * @ioc: Pointer to a Adapter Strucutre
5339 * @portnum: IOC port number
5340 *
5341 * Return: -EFAULT if read of config page header fails
5342 * or if no nvram
5343 * If read of SCSI Port Page 0 fails,
5344 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5345 * Adapter settings: async, narrow
5346 * Return 1
5347 * If read of SCSI Port Page 2 fails,
5348 * Adapter settings valid
5349 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5350 * Return 1
5351 * Else
5352 * Both valid
5353 * Return 0
5354 * CHECK - what type of locking mechanisms should be used????
5355 */
5356static int
5357mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5358{
5359 u8 *pbuf;
5360 dma_addr_t buf_dma;
5361 CONFIGPARMS cfg;
5362 ConfigPageHeader_t header;
5363 int ii;
5364 int data, rc = 0;
5365
5366 /* Allocate memory
5367 */
5368 if (!ioc->spi_data.nvram) {
5369 int sz;
5370 u8 *mem;
5371 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5372 mem = kmalloc(sz, GFP_ATOMIC);
5373 if (mem == NULL)
5374 return -EFAULT;
5375
5376 ioc->spi_data.nvram = (int *) mem;
5377
Prakash, Sathya436ace72007-07-24 15:42:08 +05305378 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005379 ioc->name, ioc->spi_data.nvram, sz));
5380 }
5381
5382 /* Invalidate NVRAM information
5383 */
5384 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5385 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5386 }
5387
5388 /* Read SPP0 header, allocate memory, then read page.
5389 */
5390 header.PageVersion = 0;
5391 header.PageLength = 0;
5392 header.PageNumber = 0;
5393 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005394 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005395 cfg.physAddr = -1;
5396 cfg.pageAddr = portnum;
5397 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5398 cfg.dir = 0;
5399 cfg.timeout = 0; /* use default */
5400 if (mpt_config(ioc, &cfg) != 0)
5401 return -EFAULT;
5402
5403 if (header.PageLength > 0) {
5404 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5405 if (pbuf) {
5406 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5407 cfg.physAddr = buf_dma;
5408 if (mpt_config(ioc, &cfg) != 0) {
5409 ioc->spi_data.maxBusWidth = MPT_NARROW;
5410 ioc->spi_data.maxSyncOffset = 0;
5411 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5412 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5413 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305414 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5415 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005416 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005417 } else {
5418 /* Save the Port Page 0 data
5419 */
5420 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5421 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5422 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5423
5424 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5425 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005426 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5427 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428 ioc->name, pPP0->Capabilities));
5429 }
5430 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5431 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5432 if (data) {
5433 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5434 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5435 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305436 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5437 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005438 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439 } else {
5440 ioc->spi_data.maxSyncOffset = 0;
5441 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5442 }
5443
5444 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5445
5446 /* Update the minSyncFactor based on bus type.
5447 */
5448 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5449 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5450
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005451 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305453 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5454 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005455 ioc->name, ioc->spi_data.minSyncFactor));
5456 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 }
5458 }
5459 if (pbuf) {
5460 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5461 }
5462 }
5463 }
5464
5465 /* SCSI Port Page 2 - Read the header then the page.
5466 */
5467 header.PageVersion = 0;
5468 header.PageLength = 0;
5469 header.PageNumber = 2;
5470 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005471 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005472 cfg.physAddr = -1;
5473 cfg.pageAddr = portnum;
5474 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5475 cfg.dir = 0;
5476 if (mpt_config(ioc, &cfg) != 0)
5477 return -EFAULT;
5478
5479 if (header.PageLength > 0) {
5480 /* Allocate memory and read SCSI Port Page 2
5481 */
5482 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5483 if (pbuf) {
5484 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5485 cfg.physAddr = buf_dma;
5486 if (mpt_config(ioc, &cfg) != 0) {
5487 /* Nvram data is left with INVALID mark
5488 */
5489 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005490 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5491
5492 /* This is an ATTO adapter, read Page2 accordingly
5493 */
5494 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5495 ATTODeviceInfo_t *pdevice = NULL;
5496 u16 ATTOFlags;
5497
5498 /* Save the Port Page 2 data
5499 * (reformat into a 32bit quantity)
5500 */
5501 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5502 pdevice = &pPP2->DeviceSettings[ii];
5503 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5504 data = 0;
5505
5506 /* Translate ATTO device flags to LSI format
5507 */
5508 if (ATTOFlags & ATTOFLAG_DISC)
5509 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5510 if (ATTOFlags & ATTOFLAG_ID_ENB)
5511 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5512 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5513 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5514 if (ATTOFlags & ATTOFLAG_TAGGED)
5515 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5516 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5517 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5518
5519 data = (data << 16) | (pdevice->Period << 8) | 10;
5520 ioc->spi_data.nvram[ii] = data;
5521 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522 } else {
5523 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5524 MpiDeviceInfo_t *pdevice = NULL;
5525
Moore, Ericd8e925d2006-01-16 18:53:06 -07005526 /*
5527 * Save "Set to Avoid SCSI Bus Resets" flag
5528 */
5529 ioc->spi_data.bus_reset =
5530 (le32_to_cpu(pPP2->PortFlags) &
5531 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5532 0 : 1 ;
5533
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 /* Save the Port Page 2 data
5535 * (reformat into a 32bit quantity)
5536 */
5537 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5538 ioc->spi_data.PortFlags = data;
5539 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5540 pdevice = &pPP2->DeviceSettings[ii];
5541 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5542 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5543 ioc->spi_data.nvram[ii] = data;
5544 }
5545 }
5546
5547 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5548 }
5549 }
5550
5551 /* Update Adapter limits with those from NVRAM
5552 * Comment: Don't need to do this. Target performance
5553 * parameters will never exceed the adapters limits.
5554 */
5555
5556 return rc;
5557}
5558
5559/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005560/**
5561 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 * @ioc: Pointer to a Adapter Strucutre
5563 * @portnum: IOC port number
5564 *
5565 * Return: -EFAULT if read of config page header fails
5566 * or 0 if success.
5567 */
5568static int
5569mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5570{
5571 CONFIGPARMS cfg;
5572 ConfigPageHeader_t header;
5573
5574 /* Read the SCSI Device Page 1 header
5575 */
5576 header.PageVersion = 0;
5577 header.PageLength = 0;
5578 header.PageNumber = 1;
5579 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005580 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 cfg.physAddr = -1;
5582 cfg.pageAddr = portnum;
5583 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5584 cfg.dir = 0;
5585 cfg.timeout = 0;
5586 if (mpt_config(ioc, &cfg) != 0)
5587 return -EFAULT;
5588
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005589 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5590 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591
5592 header.PageVersion = 0;
5593 header.PageLength = 0;
5594 header.PageNumber = 0;
5595 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5596 if (mpt_config(ioc, &cfg) != 0)
5597 return -EFAULT;
5598
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005599 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5600 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601
Prakash, Sathya436ace72007-07-24 15:42:08 +05305602 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5604
Prakash, Sathya436ace72007-07-24 15:42:08 +05305605 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5607 return 0;
5608}
5609
Eric Mooreb506ade2007-01-29 09:45:37 -07005610/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005611 * mpt_inactive_raid_list_free - This clears this link list.
5612 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005613 **/
5614static void
5615mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5616{
5617 struct inactive_raid_component_info *component_info, *pNext;
5618
5619 if (list_empty(&ioc->raid_data.inactive_list))
5620 return;
5621
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005622 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005623 list_for_each_entry_safe(component_info, pNext,
5624 &ioc->raid_data.inactive_list, list) {
5625 list_del(&component_info->list);
5626 kfree(component_info);
5627 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005628 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005629}
5630
5631/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005632 * 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 -07005633 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005634 * @ioc : pointer to per adapter structure
5635 * @channel : volume channel
5636 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005637 **/
5638static void
5639mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5640{
5641 CONFIGPARMS cfg;
5642 ConfigPageHeader_t hdr;
5643 dma_addr_t dma_handle;
5644 pRaidVolumePage0_t buffer = NULL;
5645 int i;
5646 RaidPhysDiskPage0_t phys_disk;
5647 struct inactive_raid_component_info *component_info;
5648 int handle_inactive_volumes;
5649
5650 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5651 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5652 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5653 cfg.pageAddr = (channel << 8) + id;
5654 cfg.cfghdr.hdr = &hdr;
5655 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5656
5657 if (mpt_config(ioc, &cfg) != 0)
5658 goto out;
5659
5660 if (!hdr.PageLength)
5661 goto out;
5662
5663 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5664 &dma_handle);
5665
5666 if (!buffer)
5667 goto out;
5668
5669 cfg.physAddr = dma_handle;
5670 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5671
5672 if (mpt_config(ioc, &cfg) != 0)
5673 goto out;
5674
5675 if (!buffer->NumPhysDisks)
5676 goto out;
5677
5678 handle_inactive_volumes =
5679 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5680 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5681 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5682 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5683
5684 if (!handle_inactive_volumes)
5685 goto out;
5686
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005687 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005688 for (i = 0; i < buffer->NumPhysDisks; i++) {
5689 if(mpt_raid_phys_disk_pg0(ioc,
5690 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5691 continue;
5692
5693 if ((component_info = kmalloc(sizeof (*component_info),
5694 GFP_KERNEL)) == NULL)
5695 continue;
5696
5697 component_info->volumeID = id;
5698 component_info->volumeBus = channel;
5699 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5700 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5701 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5702 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5703
5704 list_add_tail(&component_info->list,
5705 &ioc->raid_data.inactive_list);
5706 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005707 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005708
5709 out:
5710 if (buffer)
5711 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5712 dma_handle);
5713}
5714
5715/**
5716 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5717 * @ioc: Pointer to a Adapter Structure
5718 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5719 * @phys_disk: requested payload data returned
5720 *
5721 * Return:
5722 * 0 on success
5723 * -EFAULT if read of config page header fails or data pointer not NULL
5724 * -ENOMEM if pci_alloc failed
5725 **/
5726int
Kashyap, Desai2f187862009-05-29 16:52:37 +05305727mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
5728 RaidPhysDiskPage0_t *phys_disk)
Eric Mooreb506ade2007-01-29 09:45:37 -07005729{
Kashyap, Desai2f187862009-05-29 16:52:37 +05305730 CONFIGPARMS cfg;
5731 ConfigPageHeader_t hdr;
Eric Mooreb506ade2007-01-29 09:45:37 -07005732 dma_addr_t dma_handle;
5733 pRaidPhysDiskPage0_t buffer = NULL;
5734 int rc;
5735
5736 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5737 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
Kashyap, Desai2f187862009-05-29 16:52:37 +05305738 memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
Eric Mooreb506ade2007-01-29 09:45:37 -07005739
Kashyap, Desai2f187862009-05-29 16:52:37 +05305740 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
Eric Mooreb506ade2007-01-29 09:45:37 -07005741 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5742 cfg.cfghdr.hdr = &hdr;
5743 cfg.physAddr = -1;
5744 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5745
5746 if (mpt_config(ioc, &cfg) != 0) {
5747 rc = -EFAULT;
5748 goto out;
5749 }
5750
5751 if (!hdr.PageLength) {
5752 rc = -EFAULT;
5753 goto out;
5754 }
5755
5756 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5757 &dma_handle);
5758
5759 if (!buffer) {
5760 rc = -ENOMEM;
5761 goto out;
5762 }
5763
5764 cfg.physAddr = dma_handle;
5765 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5766 cfg.pageAddr = phys_disk_num;
5767
5768 if (mpt_config(ioc, &cfg) != 0) {
5769 rc = -EFAULT;
5770 goto out;
5771 }
5772
5773 rc = 0;
5774 memcpy(phys_disk, buffer, sizeof(*buffer));
5775 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5776
5777 out:
5778
5779 if (buffer)
5780 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5781 dma_handle);
5782
5783 return rc;
5784}
5785
Linus Torvalds1da177e2005-04-16 15:20:36 -07005786/**
Kashyap, Desaia7938b02009-05-29 16:53:56 +05305787 * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
5788 * @ioc: Pointer to a Adapter Structure
5789 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5790 *
5791 * Return:
5792 * returns number paths
5793 **/
5794int
5795mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
5796{
5797 CONFIGPARMS cfg;
5798 ConfigPageHeader_t hdr;
5799 dma_addr_t dma_handle;
5800 pRaidPhysDiskPage1_t buffer = NULL;
5801 int rc;
5802
5803 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5804 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5805
5806 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5807 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5808 hdr.PageNumber = 1;
5809 cfg.cfghdr.hdr = &hdr;
5810 cfg.physAddr = -1;
5811 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5812
5813 if (mpt_config(ioc, &cfg) != 0) {
5814 rc = 0;
5815 goto out;
5816 }
5817
5818 if (!hdr.PageLength) {
5819 rc = 0;
5820 goto out;
5821 }
5822
5823 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5824 &dma_handle);
5825
5826 if (!buffer) {
5827 rc = 0;
5828 goto out;
5829 }
5830
5831 cfg.physAddr = dma_handle;
5832 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5833 cfg.pageAddr = phys_disk_num;
5834
5835 if (mpt_config(ioc, &cfg) != 0) {
5836 rc = 0;
5837 goto out;
5838 }
5839
5840 rc = buffer->NumPhysDiskPaths;
5841 out:
5842
5843 if (buffer)
5844 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5845 dma_handle);
5846
5847 return rc;
5848}
5849EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
5850
5851/**
5852 * mpt_raid_phys_disk_pg1 - returns phys disk page 1
5853 * @ioc: Pointer to a Adapter Structure
5854 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5855 * @phys_disk: requested payload data returned
5856 *
5857 * Return:
5858 * 0 on success
5859 * -EFAULT if read of config page header fails or data pointer not NULL
5860 * -ENOMEM if pci_alloc failed
5861 **/
5862int
5863mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
5864 RaidPhysDiskPage1_t *phys_disk)
5865{
5866 CONFIGPARMS cfg;
5867 ConfigPageHeader_t hdr;
5868 dma_addr_t dma_handle;
5869 pRaidPhysDiskPage1_t buffer = NULL;
5870 int rc;
5871 int i;
5872 __le64 sas_address;
5873
5874 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5875 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5876 rc = 0;
5877
5878 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5879 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5880 hdr.PageNumber = 1;
5881 cfg.cfghdr.hdr = &hdr;
5882 cfg.physAddr = -1;
5883 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5884
5885 if (mpt_config(ioc, &cfg) != 0) {
5886 rc = -EFAULT;
5887 goto out;
5888 }
5889
5890 if (!hdr.PageLength) {
5891 rc = -EFAULT;
5892 goto out;
5893 }
5894
5895 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5896 &dma_handle);
5897
5898 if (!buffer) {
5899 rc = -ENOMEM;
5900 goto out;
5901 }
5902
5903 cfg.physAddr = dma_handle;
5904 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5905 cfg.pageAddr = phys_disk_num;
5906
5907 if (mpt_config(ioc, &cfg) != 0) {
5908 rc = -EFAULT;
5909 goto out;
5910 }
5911
5912 phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
5913 phys_disk->PhysDiskNum = phys_disk_num;
5914 for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
5915 phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
5916 phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
5917 phys_disk->Path[i].OwnerIdentifier =
5918 buffer->Path[i].OwnerIdentifier;
5919 phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
5920 memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
5921 sas_address = le64_to_cpu(sas_address);
5922 memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
5923 memcpy(&sas_address,
5924 &buffer->Path[i].OwnerWWID, sizeof(__le64));
5925 sas_address = le64_to_cpu(sas_address);
5926 memcpy(&phys_disk->Path[i].OwnerWWID,
5927 &sas_address, sizeof(__le64));
5928 }
5929
5930 out:
5931
5932 if (buffer)
5933 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5934 dma_handle);
5935
5936 return rc;
5937}
5938EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
5939
5940
5941/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005942 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5943 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005944 *
5945 * Return:
5946 * 0 on success
5947 * -EFAULT if read of config page header fails or data pointer not NULL
5948 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005949 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005950int
5951mpt_findImVolumes(MPT_ADAPTER *ioc)
5952{
5953 IOCPage2_t *pIoc2;
5954 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955 dma_addr_t ioc2_dma;
5956 CONFIGPARMS cfg;
5957 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005958 int rc = 0;
5959 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005960 int i;
5961
5962 if (!ioc->ir_firmware)
5963 return 0;
5964
5965 /* Free the old page
5966 */
5967 kfree(ioc->raid_data.pIocPg2);
5968 ioc->raid_data.pIocPg2 = NULL;
5969 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970
5971 /* Read IOCP2 header then the page.
5972 */
5973 header.PageVersion = 0;
5974 header.PageLength = 0;
5975 header.PageNumber = 2;
5976 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005977 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005978 cfg.physAddr = -1;
5979 cfg.pageAddr = 0;
5980 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5981 cfg.dir = 0;
5982 cfg.timeout = 0;
5983 if (mpt_config(ioc, &cfg) != 0)
5984 return -EFAULT;
5985
5986 if (header.PageLength == 0)
5987 return -EFAULT;
5988
5989 iocpage2sz = header.PageLength * 4;
5990 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5991 if (!pIoc2)
5992 return -ENOMEM;
5993
5994 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5995 cfg.physAddr = ioc2_dma;
5996 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005997 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005998
Eric Mooreb506ade2007-01-29 09:45:37 -07005999 mem = kmalloc(iocpage2sz, GFP_KERNEL);
Julia Lawall1c1acab2010-08-11 12:11:24 +02006000 if (!mem) {
6001 rc = -ENOMEM;
Eric Mooreb506ade2007-01-29 09:45:37 -07006002 goto out;
Julia Lawall1c1acab2010-08-11 12:11:24 +02006003 }
Eric Mooreb506ade2007-01-29 09:45:37 -07006004
Linus Torvalds1da177e2005-04-16 15:20:36 -07006005 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07006006 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006007
Eric Mooreb506ade2007-01-29 09:45:37 -07006008 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006009
Eric Mooreb506ade2007-01-29 09:45:37 -07006010 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
6011 mpt_inactive_raid_volumes(ioc,
6012 pIoc2->RaidVolume[i].VolumeBus,
6013 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006014
Eric Mooreb506ade2007-01-29 09:45:37 -07006015 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006016 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
6017
6018 return rc;
6019}
6020
Moore, Ericc972c702006-03-14 09:14:06 -07006021static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07006022mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
6023{
6024 IOCPage3_t *pIoc3;
6025 u8 *mem;
6026 CONFIGPARMS cfg;
6027 ConfigPageHeader_t header;
6028 dma_addr_t ioc3_dma;
6029 int iocpage3sz = 0;
6030
6031 /* Free the old page
6032 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006033 kfree(ioc->raid_data.pIocPg3);
6034 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006035
6036 /* There is at least one physical disk.
6037 * Read and save IOC Page 3
6038 */
6039 header.PageVersion = 0;
6040 header.PageLength = 0;
6041 header.PageNumber = 3;
6042 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006043 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006044 cfg.physAddr = -1;
6045 cfg.pageAddr = 0;
6046 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6047 cfg.dir = 0;
6048 cfg.timeout = 0;
6049 if (mpt_config(ioc, &cfg) != 0)
6050 return 0;
6051
6052 if (header.PageLength == 0)
6053 return 0;
6054
6055 /* Read Header good, alloc memory
6056 */
6057 iocpage3sz = header.PageLength * 4;
6058 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
6059 if (!pIoc3)
6060 return 0;
6061
6062 /* Read the Page and save the data
6063 * into malloc'd memory.
6064 */
6065 cfg.physAddr = ioc3_dma;
6066 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6067 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07006068 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006069 if (mem) {
6070 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006071 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072 }
6073 }
6074
6075 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
6076
6077 return 0;
6078}
6079
6080static void
6081mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
6082{
6083 IOCPage4_t *pIoc4;
6084 CONFIGPARMS cfg;
6085 ConfigPageHeader_t header;
6086 dma_addr_t ioc4_dma;
6087 int iocpage4sz;
6088
6089 /* Read and save IOC Page 4
6090 */
6091 header.PageVersion = 0;
6092 header.PageLength = 0;
6093 header.PageNumber = 4;
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 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
6108 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
6109 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
6110 if (!pIoc4)
6111 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06006112 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006113 } else {
6114 ioc4_dma = ioc->spi_data.IocPg4_dma;
6115 iocpage4sz = ioc->spi_data.IocPg4Sz;
6116 }
6117
6118 /* Read the Page into dma memory.
6119 */
6120 cfg.physAddr = ioc4_dma;
6121 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6122 if (mpt_config(ioc, &cfg) == 0) {
6123 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
6124 ioc->spi_data.IocPg4_dma = ioc4_dma;
6125 ioc->spi_data.IocPg4Sz = iocpage4sz;
6126 } else {
6127 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
6128 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06006129 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006130 }
6131}
6132
6133static void
6134mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
6135{
6136 IOCPage1_t *pIoc1;
6137 CONFIGPARMS cfg;
6138 ConfigPageHeader_t header;
6139 dma_addr_t ioc1_dma;
6140 int iocpage1sz = 0;
6141 u32 tmp;
6142
6143 /* Check the Coalescing Timeout in IOC Page 1
6144 */
6145 header.PageVersion = 0;
6146 header.PageLength = 0;
6147 header.PageNumber = 1;
6148 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006149 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006150 cfg.physAddr = -1;
6151 cfg.pageAddr = 0;
6152 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6153 cfg.dir = 0;
6154 cfg.timeout = 0;
6155 if (mpt_config(ioc, &cfg) != 0)
6156 return;
6157
6158 if (header.PageLength == 0)
6159 return;
6160
6161 /* Read Header good, alloc memory
6162 */
6163 iocpage1sz = header.PageLength * 4;
6164 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
6165 if (!pIoc1)
6166 return;
6167
6168 /* Read the Page and check coalescing timeout
6169 */
6170 cfg.physAddr = ioc1_dma;
6171 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6172 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306173
Linus Torvalds1da177e2005-04-16 15:20:36 -07006174 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
6175 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
6176 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
6177
Prakash, Sathya436ace72007-07-24 15:42:08 +05306178 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006179 ioc->name, tmp));
6180
6181 if (tmp > MPT_COALESCING_TIMEOUT) {
6182 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
6183
6184 /* Write NVRAM and current
6185 */
6186 cfg.dir = 1;
6187 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
6188 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306189 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006190 ioc->name, MPT_COALESCING_TIMEOUT));
6191
6192 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
6193 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306194 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6195 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006196 ioc->name, MPT_COALESCING_TIMEOUT));
6197 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306198 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6199 "Reset NVRAM Coalescing Timeout Failed\n",
6200 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006201 }
6202
6203 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306204 dprintk(ioc, printk(MYIOC_s_WARN_FMT
6205 "Reset of Current Coalescing Timeout Failed!\n",
6206 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006207 }
6208 }
6209
6210 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306211 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006212 }
6213 }
6214
6215 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
6216
6217 return;
6218}
6219
Prakash, Sathyaedb90682007-07-17 14:39:14 +05306220static void
6221mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
6222{
6223 CONFIGPARMS cfg;
6224 ConfigPageHeader_t hdr;
6225 dma_addr_t buf_dma;
6226 ManufacturingPage0_t *pbuf = NULL;
6227
6228 memset(&cfg, 0 , sizeof(CONFIGPARMS));
6229 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
6230
6231 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
6232 cfg.cfghdr.hdr = &hdr;
6233 cfg.physAddr = -1;
6234 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6235 cfg.timeout = 10;
6236
6237 if (mpt_config(ioc, &cfg) != 0)
6238 goto out;
6239
6240 if (!cfg.cfghdr.hdr->PageLength)
6241 goto out;
6242
6243 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6244 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
6245 if (!pbuf)
6246 goto out;
6247
6248 cfg.physAddr = buf_dma;
6249
6250 if (mpt_config(ioc, &cfg) != 0)
6251 goto out;
6252
6253 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
6254 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
6255 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
6256
6257 out:
6258
6259 if (pbuf)
6260 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
6261}
6262
Linus Torvalds1da177e2005-04-16 15:20:36 -07006263/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006264/**
6265 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006266 * @ioc: Pointer to MPT_ADAPTER structure
6267 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05306268 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07006269 */
6270static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05306271SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006272{
Kashyap, Desaifd761752009-05-29 16:39:06 +05306273 EventNotification_t evn;
6274 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006275
Kashyap, Desaifd761752009-05-29 16:39:06 +05306276 memset(&evn, 0, sizeof(EventNotification_t));
6277 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006278
Kashyap, Desaifd761752009-05-29 16:39:06 +05306279 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
6280 evn.Switch = EvSwitch;
6281 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006282
Kashyap, Desaifd761752009-05-29 16:39:06 +05306283 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6284 "Sending EventNotification (%d) request %p\n",
6285 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006286
Kashyap, Desaifd761752009-05-29 16:39:06 +05306287 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6288 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6289 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006290}
6291
6292/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6293/**
6294 * SendEventAck - Send EventAck request to MPT adapter.
6295 * @ioc: Pointer to MPT_ADAPTER structure
6296 * @evnp: Pointer to original EventNotification request
6297 */
6298static int
6299SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6300{
6301 EventAck_t *pAck;
6302
6303 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306304 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306305 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006306 return -1;
6307 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006308
Prakash, Sathya436ace72007-07-24 15:42:08 +05306309 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006310
6311 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6312 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006313 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006314 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006315 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006316 pAck->Event = evnp->Event;
6317 pAck->EventContext = evnp->EventContext;
6318
6319 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6320
6321 return 0;
6322}
6323
6324/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6325/**
6326 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006327 * @ioc: Pointer to an adapter structure
6328 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006329 * action, page address, direction, physical address
6330 * and pointer to a configuration page header
6331 * Page header is updated.
6332 *
6333 * Returns 0 for success
6334 * -EPERM if not allowed due to ISR context
6335 * -EAGAIN if no msg frames currently available
6336 * -EFAULT for non-successful reply or no reply (timeout)
6337 */
6338int
6339mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6340{
6341 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306342 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006343 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006344 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306345 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006346 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306347 long timeout;
6348 int ret;
6349 u8 page_type = 0, extend_page;
6350 unsigned long timeleft;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306351 unsigned long flags;
6352 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306353 u8 issue_hard_reset = 0;
6354 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006355
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006356 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006357 * to be in ISR context, because that is fatal!
6358 */
6359 in_isr = in_interrupt();
6360 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306361 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006362 ioc->name));
6363 return -EPERM;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306364 }
6365
6366 /* don't send a config page during diag reset */
6367 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6368 if (ioc->ioc_reset_in_progress) {
6369 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6370 "%s: busy with host reset\n", ioc->name, __func__));
6371 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6372 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006373 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306374 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006375
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306376 /* don't send if no chance of success */
6377 if (!ioc->active ||
6378 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6379 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6380 "%s: ioc not operational, %d, %xh\n",
6381 ioc->name, __func__, ioc->active,
6382 mpt_GetIocState(ioc, 0)));
6383 return -EFAULT;
6384 }
6385
6386 retry_config:
6387 mutex_lock(&ioc->mptbase_cmds.mutex);
6388 /* init the internal cmd struct */
6389 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6390 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6391
Linus Torvalds1da177e2005-04-16 15:20:36 -07006392 /* Get and Populate a free Frame
6393 */
6394 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306395 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6396 "mpt_config: no msg frames!\n", ioc->name));
6397 ret = -EAGAIN;
6398 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006399 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306400
Linus Torvalds1da177e2005-04-16 15:20:36 -07006401 pReq = (Config_t *)mf;
6402 pReq->Action = pCfg->action;
6403 pReq->Reserved = 0;
6404 pReq->ChainOffset = 0;
6405 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006406
6407 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006408 pReq->ExtPageLength = 0;
6409 pReq->ExtPageType = 0;
6410 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006411
Linus Torvalds1da177e2005-04-16 15:20:36 -07006412 for (ii=0; ii < 8; ii++)
6413 pReq->Reserved2[ii] = 0;
6414
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006415 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6416 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6417 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6418 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6419
6420 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6421 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6422 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6423 pReq->ExtPageType = pExtHdr->ExtPageType;
6424 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6425
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306426 /* Page Length must be treated as a reserved field for the
6427 * extended header.
6428 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006429 pReq->Header.PageLength = 0;
6430 }
6431
Linus Torvalds1da177e2005-04-16 15:20:36 -07006432 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6433
6434 /* Add a SGE to the config request.
6435 */
6436 if (pCfg->dir)
6437 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6438 else
6439 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6440
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306441 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6442 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006443 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306444 page_type = pReq->ExtPageType;
6445 extend_page = 1;
6446 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006447 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306448 page_type = pReq->Header.PageType;
6449 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006450 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006451
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306452 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6453 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6454 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6455
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306456 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306457 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006458 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306459 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6460 timeout);
6461 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6462 ret = -ETIME;
6463 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6464 "Failed Sending Config request type 0x%x, page 0x%x,"
6465 " action %d, status %xh, time left %ld\n\n",
6466 ioc->name, page_type, pReq->Header.PageNumber,
6467 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6468 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6469 goto out;
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05306470 if (!timeleft) {
6471 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6472 if (ioc->ioc_reset_in_progress) {
6473 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
6474 flags);
6475 printk(MYIOC_s_INFO_FMT "%s: host reset in"
6476 " progress mpt_config timed out.!!\n",
6477 __func__, ioc->name);
Dan Carpenter83ff74e2011-08-27 12:59:30 +03006478 mutex_unlock(&ioc->mptbase_cmds.mutex);
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05306479 return -EFAULT;
6480 }
6481 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306482 issue_hard_reset = 1;
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05306483 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306484 goto out;
6485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006486
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306487 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6488 ret = -1;
6489 goto out;
6490 }
6491 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6492 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6493 if (ret == MPI_IOCSTATUS_SUCCESS) {
6494 if (extend_page) {
6495 pCfg->cfghdr.ehdr->ExtPageLength =
6496 le16_to_cpu(pReply->ExtPageLength);
6497 pCfg->cfghdr.ehdr->ExtPageType =
6498 pReply->ExtPageType;
6499 }
6500 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6501 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6502 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6503 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006504
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006506
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306507 if (retry_count)
6508 printk(MYIOC_s_INFO_FMT "Retry completed "
6509 "ret=0x%x timeleft=%ld\n",
6510 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006511
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306512 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6513 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006514
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306515out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006516
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306517 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6518 mutex_unlock(&ioc->mptbase_cmds.mutex);
6519 if (issue_hard_reset) {
6520 issue_hard_reset = 0;
Kei Tokunaga97009a22010-06-22 19:01:51 +09006521 printk(MYIOC_s_WARN_FMT
6522 "Issuing Reset from %s!!, doorbell=0x%08x\n",
6523 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaib3b97312010-03-18 19:14:51 +05306524 if (retry_count == 0) {
6525 if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0)
6526 retry_count++;
6527 } else
6528 mpt_HardResetHandler(ioc, CAN_SLEEP);
6529
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306530 mpt_free_msg_frame(ioc, mf);
6531 /* attempt one retry for a timed out command */
Kashyap, Desaib3b97312010-03-18 19:14:51 +05306532 if (retry_count < 2) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306533 printk(MYIOC_s_INFO_FMT
6534 "Attempting Retry Config request"
6535 " type 0x%x, page 0x%x,"
6536 " action %d\n", ioc->name, page_type,
6537 pCfg->cfghdr.hdr->PageNumber, pCfg->action);
6538 retry_count++;
6539 goto retry_config;
6540 }
6541 }
6542 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006543
Linus Torvalds1da177e2005-04-16 15:20:36 -07006544}
6545
6546/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006547/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006548 * mpt_ioc_reset - Base cleanup for hard reset
6549 * @ioc: Pointer to the adapter structure
6550 * @reset_phase: Indicates pre- or post-reset functionality
6551 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006552 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006553 */
6554static int
6555mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6556{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306557 switch (reset_phase) {
6558 case MPT_IOC_SETUP_RESET:
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306559 ioc->taskmgmt_quiesce_io = 1;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306560 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6561 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
6562 break;
6563 case MPT_IOC_PRE_RESET:
6564 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6565 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
6566 break;
6567 case MPT_IOC_POST_RESET:
6568 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6569 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
6570/* wake up mptbase_cmds */
6571 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6572 ioc->mptbase_cmds.status |=
6573 MPT_MGMT_STATUS_DID_IOCRESET;
6574 complete(&ioc->mptbase_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006575 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306576/* wake up taskmgmt_cmds */
6577 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
6578 ioc->taskmgmt_cmds.status |=
6579 MPT_MGMT_STATUS_DID_IOCRESET;
6580 complete(&ioc->taskmgmt_cmds.done);
6581 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306582 break;
6583 default:
6584 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006585 }
6586
6587 return 1; /* currently means nothing really */
6588}
6589
6590
6591#ifdef CONFIG_PROC_FS /* { */
6592/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6593/*
6594 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6595 */
6596/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006597/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006598 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6599 *
6600 * Returns 0 for success, non-zero for failure.
6601 */
6602static int
6603procmpt_create(void)
6604{
Linus Torvalds1da177e2005-04-16 15:20:36 -07006605 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6606 if (mpt_proc_root_dir == NULL)
6607 return -ENOTDIR;
6608
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006609 proc_create("summary", S_IRUGO, mpt_proc_root_dir, &mpt_summary_proc_fops);
6610 proc_create("version", S_IRUGO, mpt_proc_root_dir, &mpt_version_proc_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006611 return 0;
6612}
6613
6614/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006615/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006616 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6617 *
6618 * Returns 0 for success, non-zero for failure.
6619 */
6620static void
6621procmpt_destroy(void)
6622{
6623 remove_proc_entry("version", mpt_proc_root_dir);
6624 remove_proc_entry("summary", mpt_proc_root_dir);
6625 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6626}
6627
6628/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlap1f5cfe22010-08-14 13:05:50 -07006629/*
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006630 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006631 */
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006632static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan);
6633
6634static int mpt_summary_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006635{
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006636 MPT_ADAPTER *ioc = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006637
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006638 if (ioc) {
6639 seq_mpt_print_ioc_summary(ioc, m, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006640 } else {
6641 list_for_each_entry(ioc, &ioc_list, list) {
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006642 seq_mpt_print_ioc_summary(ioc, m, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006643 }
6644 }
6645
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006646 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006647}
6648
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006649static int mpt_summary_proc_open(struct inode *inode, struct file *file)
6650{
Al Virod9dda782013-03-31 18:16:14 -04006651 return single_open(file, mpt_summary_proc_show, PDE_DATA(inode));
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006652}
6653
6654static const struct file_operations mpt_summary_proc_fops = {
6655 .owner = THIS_MODULE,
6656 .open = mpt_summary_proc_open,
6657 .read = seq_read,
6658 .llseek = seq_lseek,
6659 .release = single_release,
6660};
6661
6662static int mpt_version_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006663{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306664 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006665 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006666 char *drvname;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006667
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006668 seq_printf(m, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6669 seq_printf(m, " Fusion MPT base driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006670
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006671 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006672 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006673 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306674 if (MptCallbacks[cb_idx]) {
6675 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006676 case MPTSPI_DRIVER:
6677 if (!scsi++) drvname = "SPI host";
6678 break;
6679 case MPTFC_DRIVER:
6680 if (!fc++) drvname = "FC host";
6681 break;
6682 case MPTSAS_DRIVER:
6683 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006684 break;
6685 case MPTLAN_DRIVER:
6686 if (!lan++) drvname = "LAN";
6687 break;
6688 case MPTSTM_DRIVER:
6689 if (!targ++) drvname = "SCSI target";
6690 break;
6691 case MPTCTL_DRIVER:
6692 if (!ctl++) drvname = "ioctl";
6693 break;
6694 }
6695
6696 if (drvname)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006697 seq_printf(m, " Fusion MPT %s driver\n", drvname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006698 }
6699 }
6700
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006701 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006702}
6703
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006704static int mpt_version_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006705{
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006706 return single_open(file, mpt_version_proc_show, NULL);
6707}
6708
6709static const struct file_operations mpt_version_proc_fops = {
6710 .owner = THIS_MODULE,
6711 .open = mpt_version_proc_open,
6712 .read = seq_read,
6713 .llseek = seq_lseek,
6714 .release = single_release,
6715};
6716
6717static int mpt_iocinfo_proc_show(struct seq_file *m, void *v)
6718{
6719 MPT_ADAPTER *ioc = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006720 char expVer[32];
6721 int sz;
6722 int p;
6723
6724 mpt_get_fw_exp_ver(expVer, ioc);
6725
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006726 seq_printf(m, "%s:", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006727 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006728 seq_printf(m, " (f/w download boot flag set)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006729// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006730// seq_printf(m, " CONFIG_CHECKSUM_FAIL!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006731
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006732 seq_printf(m, "\n ProductID = 0x%04x (%s)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006733 ioc->facts.ProductID,
6734 ioc->prod_name);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006735 seq_printf(m, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006736 if (ioc->facts.FWImageSize)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006737 seq_printf(m, " (fw_size=%d)", ioc->facts.FWImageSize);
6738 seq_printf(m, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6739 seq_printf(m, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6740 seq_printf(m, " EventState = 0x%02x\n", ioc->facts.EventState);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006741
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006742 seq_printf(m, " CurrentHostMfaHighAddr = 0x%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006743 ioc->facts.CurrentHostMfaHighAddr);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006744 seq_printf(m, " CurrentSenseBufferHighAddr = 0x%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006745 ioc->facts.CurrentSenseBufferHighAddr);
6746
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006747 seq_printf(m, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6748 seq_printf(m, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006749
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006750 seq_printf(m, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006751 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6752 /*
6753 * Rounding UP to nearest 4-kB boundary here...
6754 */
6755 sz = (ioc->req_sz * ioc->req_depth) + 128;
6756 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006757 seq_printf(m, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006758 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006759 seq_printf(m, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006760 4*ioc->facts.RequestFrameSize,
6761 ioc->facts.GlobalCredits);
6762
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006763 seq_printf(m, " Frames @ 0x%p (Dma @ 0x%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006764 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6765 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006766 seq_printf(m, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006767 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006768 seq_printf(m, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006769 ioc->facts.CurReplyFrameSize,
6770 ioc->facts.ReplyQueueDepth);
6771
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006772 seq_printf(m, " MaxDevices = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006773 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006774 seq_printf(m, " MaxBuses = %d\n", ioc->facts.MaxBuses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006775
6776 /* per-port info */
6777 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006778 seq_printf(m, " PortNumber = %d (of %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006779 p+1,
6780 ioc->facts.NumberOfPorts);
6781 if (ioc->bus_type == FC) {
6782 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6783 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006784 seq_printf(m, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006785 a[5], a[4], a[3], a[2], a[1], a[0]);
6786 }
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006787 seq_printf(m, " WWN = %08X%08X:%08X%08X\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006788 ioc->fc_port_page0[p].WWNN.High,
6789 ioc->fc_port_page0[p].WWNN.Low,
6790 ioc->fc_port_page0[p].WWPN.High,
6791 ioc->fc_port_page0[p].WWPN.Low);
6792 }
6793 }
6794
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006795 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006796}
6797
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006798static int mpt_iocinfo_proc_open(struct inode *inode, struct file *file)
6799{
Al Virod9dda782013-03-31 18:16:14 -04006800 return single_open(file, mpt_iocinfo_proc_show, PDE_DATA(inode));
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006801}
6802
6803static const struct file_operations mpt_iocinfo_proc_fops = {
6804 .owner = THIS_MODULE,
6805 .open = mpt_iocinfo_proc_open,
6806 .read = seq_read,
6807 .llseek = seq_lseek,
6808 .release = single_release,
6809};
Linus Torvalds1da177e2005-04-16 15:20:36 -07006810#endif /* CONFIG_PROC_FS } */
6811
6812/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6813static void
6814mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6815{
6816 buf[0] ='\0';
6817 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6818 sprintf(buf, " (Exp %02d%02d)",
6819 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6820 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6821
6822 /* insider hack! */
6823 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6824 strcat(buf, " [MDBG]");
6825 }
6826}
6827
6828/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6829/**
6830 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6831 * @ioc: Pointer to MPT_ADAPTER structure
6832 * @buffer: Pointer to buffer where IOC summary info should be written
6833 * @size: Pointer to number of bytes we wrote (set by this routine)
6834 * @len: Offset at which to start writing in buffer
6835 * @showlan: Display LAN stuff?
6836 *
6837 * This routine writes (english readable) ASCII text, which represents
6838 * a summary of IOC information, to a buffer.
6839 */
6840void
6841mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6842{
6843 char expVer[32];
6844 int y;
6845
6846 mpt_get_fw_exp_ver(expVer, ioc);
6847
6848 /*
6849 * Shorter summary of attached ioc's...
6850 */
6851 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6852 ioc->name,
6853 ioc->prod_name,
6854 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6855 ioc->facts.FWVersion.Word,
6856 expVer,
6857 ioc->facts.NumberOfPorts,
6858 ioc->req_depth);
6859
6860 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6861 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6862 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6863 a[5], a[4], a[3], a[2], a[1], a[0]);
6864 }
6865
Linus Torvalds1da177e2005-04-16 15:20:36 -07006866 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006867
6868 if (!ioc->active)
6869 y += sprintf(buffer+len+y, " (disabled)");
6870
6871 y += sprintf(buffer+len+y, "\n");
6872
6873 *size = y;
6874}
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006875
6876static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan)
6877{
6878 char expVer[32];
6879
6880 mpt_get_fw_exp_ver(expVer, ioc);
6881
6882 /*
6883 * Shorter summary of attached ioc's...
6884 */
6885 seq_printf(m, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6886 ioc->name,
6887 ioc->prod_name,
6888 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6889 ioc->facts.FWVersion.Word,
6890 expVer,
6891 ioc->facts.NumberOfPorts,
6892 ioc->req_depth);
6893
6894 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6895 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6896 seq_printf(m, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6897 a[5], a[4], a[3], a[2], a[1], a[0]);
6898 }
6899
6900 seq_printf(m, ", IRQ=%d", ioc->pci_irq);
6901
6902 if (!ioc->active)
6903 seq_printf(m, " (disabled)");
6904
6905 seq_putc(m, '\n');
6906}
6907
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306908/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006909 * mpt_set_taskmgmt_in_progress_flag - set flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306910 * @ioc: Pointer to MPT_ADAPTER structure
6911 *
6912 * Returns 0 for SUCCESS or -1 if FAILED.
6913 *
6914 * If -1 is return, then it was not possible to set the flags
6915 **/
6916int
6917mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6918{
6919 unsigned long flags;
6920 int retval;
6921
6922 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6923 if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
6924 (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
6925 retval = -1;
6926 goto out;
6927 }
6928 retval = 0;
6929 ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306930 ioc->taskmgmt_quiesce_io = 1;
6931 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306932 ioc->alt_ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306933 ioc->alt_ioc->taskmgmt_quiesce_io = 1;
6934 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306935 out:
6936 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6937 return retval;
6938}
6939EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
6940
6941/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006942 * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306943 * @ioc: Pointer to MPT_ADAPTER structure
6944 *
6945 **/
6946void
6947mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6948{
6949 unsigned long flags;
6950
6951 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6952 ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306953 ioc->taskmgmt_quiesce_io = 0;
6954 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306955 ioc->alt_ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306956 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
6957 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306958 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6959}
6960EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006961
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306962
6963/**
6964 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6965 * the kernel
6966 * @ioc: Pointer to MPT_ADAPTER structure
6967 *
6968 **/
6969void
6970mpt_halt_firmware(MPT_ADAPTER *ioc)
6971{
6972 u32 ioc_raw_state;
6973
6974 ioc_raw_state = mpt_GetIocState(ioc, 0);
6975
6976 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6977 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6978 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6979 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6980 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6981 } else {
6982 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6983 panic("%s: Firmware is halted due to command timeout\n",
6984 ioc->name);
6985 }
6986}
6987EXPORT_SYMBOL(mpt_halt_firmware);
6988
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306989/**
6990 * mpt_SoftResetHandler - Issues a less expensive reset
6991 * @ioc: Pointer to MPT_ADAPTER structure
6992 * @sleepFlag: Indicates if sleep or schedule must be called.
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306993 *
6994 * Returns 0 for SUCCESS or -1 if FAILED.
6995 *
6996 * Message Unit Reset - instructs the IOC to reset the Reply Post and
6997 * Free FIFO's. All the Message Frames on Reply Free FIFO are discarded.
6998 * All posted buffers are freed, and event notification is turned off.
Lucas De Marchi25985ed2011-03-30 22:57:33 -03006999 * IOC doesn't reply to any outstanding request. This will transfer IOC
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05307000 * to READY state.
7001 **/
Joe Lawrence5767d252014-06-25 17:05:49 -04007002static int
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05307003mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
7004{
7005 int rc;
7006 int ii;
7007 u8 cb_idx;
7008 unsigned long flags;
7009 u32 ioc_state;
7010 unsigned long time_count;
7011
7012 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n",
7013 ioc->name));
7014
7015 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
7016
7017 if (mpt_fwfault_debug)
7018 mpt_halt_firmware(ioc);
7019
7020 if (ioc_state == MPI_IOC_STATE_FAULT ||
7021 ioc_state == MPI_IOC_STATE_RESET) {
7022 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7023 "skipping, either in FAULT or RESET state!\n", ioc->name));
7024 return -1;
7025 }
7026
7027 if (ioc->bus_type == FC) {
7028 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7029 "skipping, because the bus type is FC!\n", ioc->name));
7030 return -1;
7031 }
7032
7033 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7034 if (ioc->ioc_reset_in_progress) {
7035 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7036 return -1;
7037 }
7038 ioc->ioc_reset_in_progress = 1;
7039 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7040
7041 rc = -1;
7042
7043 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7044 if (MptResetHandlers[cb_idx])
7045 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
7046 }
7047
7048 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7049 if (ioc->taskmgmt_in_progress) {
Kashyap, Desaib9a0f872010-06-17 14:42:39 +05307050 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05307051 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7052 return -1;
7053 }
7054 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7055 /* Disable reply interrupts (also blocks FreeQ) */
7056 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
7057 ioc->active = 0;
7058 time_count = jiffies;
7059
7060 rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
7061
7062 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7063 if (MptResetHandlers[cb_idx])
7064 mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
7065 }
7066
7067 if (rc)
7068 goto out;
7069
7070 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
7071 if (ioc_state != MPI_IOC_STATE_READY)
7072 goto out;
7073
7074 for (ii = 0; ii < 5; ii++) {
7075 /* Get IOC facts! Allow 5 retries */
7076 rc = GetIocFacts(ioc, sleepFlag,
7077 MPT_HOSTEVENT_IOC_RECOVER);
7078 if (rc == 0)
7079 break;
7080 if (sleepFlag == CAN_SLEEP)
7081 msleep(100);
7082 else
7083 mdelay(100);
7084 }
7085 if (ii == 5)
7086 goto out;
7087
7088 rc = PrimeIocFifos(ioc);
7089 if (rc != 0)
7090 goto out;
7091
7092 rc = SendIocInit(ioc, sleepFlag);
7093 if (rc != 0)
7094 goto out;
7095
7096 rc = SendEventNotification(ioc, 1, sleepFlag);
7097 if (rc != 0)
7098 goto out;
7099
7100 if (ioc->hard_resets < -1)
7101 ioc->hard_resets++;
7102
7103 /*
7104 * At this point, we know soft reset succeeded.
7105 */
7106
7107 ioc->active = 1;
7108 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
7109
7110 out:
7111 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7112 ioc->ioc_reset_in_progress = 0;
7113 ioc->taskmgmt_quiesce_io = 0;
7114 ioc->taskmgmt_in_progress = 0;
7115 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7116
7117 if (ioc->active) { /* otherwise, hard reset coming */
7118 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7119 if (MptResetHandlers[cb_idx])
7120 mpt_signal_reset(cb_idx, ioc,
7121 MPT_IOC_POST_RESET);
7122 }
7123 }
7124
7125 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7126 "SoftResetHandler: completed (%d seconds): %s\n",
7127 ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,
7128 ((rc == 0) ? "SUCCESS" : "FAILED")));
7129
7130 return rc;
7131}
7132
7133/**
7134 * mpt_Soft_Hard_ResetHandler - Try less expensive reset
7135 * @ioc: Pointer to MPT_ADAPTER structure
7136 * @sleepFlag: Indicates if sleep or schedule must be called.
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05307137 *
7138 * Returns 0 for SUCCESS or -1 if FAILED.
7139 * Try for softreset first, only if it fails go for expensive
7140 * HardReset.
7141 **/
7142int
7143mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag) {
7144 int ret = -1;
7145
7146 ret = mpt_SoftResetHandler(ioc, sleepFlag);
7147 if (ret == 0)
7148 return ret;
7149 ret = mpt_HardResetHandler(ioc, sleepFlag);
7150 return ret;
7151}
7152EXPORT_SYMBOL(mpt_Soft_Hard_ResetHandler);
7153
Linus Torvalds1da177e2005-04-16 15:20:36 -07007154/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7155/*
7156 * Reset Handling
7157 */
7158/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7159/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007160 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07007161 * @ioc: Pointer to MPT_ADAPTER structure
7162 * @sleepFlag: Indicates if sleep or schedule must be called.
7163 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007164 * Issues SCSI Task Management call based on input arg values.
7165 * If TaskMgmt fails, returns associated SCSI request.
7166 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07007167 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
7168 * or a non-interrupt thread. In the former, must not call schedule().
7169 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007170 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07007171 * FW reload/initialization failed.
7172 *
7173 * Returns 0 for SUCCESS or -1 if FAILED.
7174 */
7175int
7176mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
7177{
Kashyap, Desaid1306912009-08-05 12:53:51 +05307178 int rc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307179 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007180 unsigned long flags;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307181 unsigned long time_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007182
Prakash, Sathya436ace72007-07-24 15:42:08 +05307183 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007184#ifdef MFCNT
7185 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
7186 printk("MF count 0x%x !\n", ioc->mfcnt);
7187#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05307188 if (mpt_fwfault_debug)
7189 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007190
7191 /* Reset the adapter. Prevent more than 1 call to
7192 * mpt_do_ioc_recovery at any instant in time.
7193 */
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307194 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7195 if (ioc->ioc_reset_in_progress) {
7196 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05307197 ioc->wait_on_reset_completion = 1;
7198 do {
7199 ssleep(1);
7200 } while (ioc->ioc_reset_in_progress == 1);
7201 ioc->wait_on_reset_completion = 0;
7202 return ioc->reset_status;
7203 }
7204 if (ioc->wait_on_reset_completion) {
7205 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7206 rc = 0;
7207 time_count = jiffies;
7208 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007209 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307210 ioc->ioc_reset_in_progress = 1;
7211 if (ioc->alt_ioc)
7212 ioc->alt_ioc->ioc_reset_in_progress = 1;
7213 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007214
Linus Torvalds1da177e2005-04-16 15:20:36 -07007215
7216 /* The SCSI driver needs to adjust timeouts on all current
7217 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02007218 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007219 * For all other protocol drivers, this is a no-op.
7220 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05307221 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7222 if (MptResetHandlers[cb_idx]) {
7223 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
7224 if (ioc->alt_ioc)
7225 mpt_signal_reset(cb_idx, ioc->alt_ioc,
7226 MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007227 }
7228 }
7229
Kashyap, Desai2f187862009-05-29 16:52:37 +05307230 time_count = jiffies;
7231 rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
7232 if (rc != 0) {
7233 printk(KERN_WARNING MYNAM
Kei Tokunaga97009a22010-06-22 19:01:51 +09007234 ": WARNING - (%d) Cannot recover %s, doorbell=0x%08x\n",
7235 rc, ioc->name, mpt_GetIocState(ioc, 0));
Kashyap, Desai2f187862009-05-29 16:52:37 +05307236 } else {
7237 if (ioc->hard_resets < -1)
7238 ioc->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007239 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007240
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307241 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7242 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307243 ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307244 ioc->taskmgmt_in_progress = 0;
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05307245 ioc->reset_status = rc;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307246 if (ioc->alt_ioc) {
7247 ioc->alt_ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307248 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307249 ioc->alt_ioc->taskmgmt_in_progress = 0;
7250 }
7251 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007252
Kashyap, Desaid1306912009-08-05 12:53:51 +05307253 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7254 if (MptResetHandlers[cb_idx]) {
7255 mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
7256 if (ioc->alt_ioc)
7257 mpt_signal_reset(cb_idx,
7258 ioc->alt_ioc, MPT_IOC_POST_RESET);
7259 }
7260 }
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05307261exit:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307262 dtmprintk(ioc,
7263 printk(MYIOC_s_DEBUG_FMT
7264 "HardResetHandler: completed (%d seconds): %s\n", ioc->name,
7265 jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?
7266 "SUCCESS" : "FAILED")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007267
7268 return rc;
7269}
7270
Kashyap, Desai2f187862009-05-29 16:52:37 +05307271#ifdef CONFIG_FUSION_LOGGING
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007272static void
Kashyap, Desai2f187862009-05-29 16:52:37 +05307273mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007274{
Eric Moore509e5e52006-04-26 13:22:37 -06007275 char *ds = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307276 u32 evData0;
7277 int ii;
7278 u8 event;
7279 char *evStr = ioc->evStr;
7280
7281 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7282 evData0 = le32_to_cpu(pEventReply->Data[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007283
7284 switch(event) {
7285 case MPI_EVENT_NONE:
7286 ds = "None";
7287 break;
7288 case MPI_EVENT_LOG_DATA:
7289 ds = "Log Data";
7290 break;
7291 case MPI_EVENT_STATE_CHANGE:
7292 ds = "State Change";
7293 break;
7294 case MPI_EVENT_UNIT_ATTENTION:
7295 ds = "Unit Attention";
7296 break;
7297 case MPI_EVENT_IOC_BUS_RESET:
7298 ds = "IOC Bus Reset";
7299 break;
7300 case MPI_EVENT_EXT_BUS_RESET:
7301 ds = "External Bus Reset";
7302 break;
7303 case MPI_EVENT_RESCAN:
7304 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007305 break;
7306 case MPI_EVENT_LINK_STATUS_CHANGE:
7307 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
7308 ds = "Link Status(FAILURE) Change";
7309 else
7310 ds = "Link Status(ACTIVE) Change";
7311 break;
7312 case MPI_EVENT_LOOP_STATE_CHANGE:
7313 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
7314 ds = "Loop State(LIP) Change";
7315 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Kashyap, Desai2f187862009-05-29 16:52:37 +05307316 ds = "Loop State(LPE) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007317 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05307318 ds = "Loop State(LPB) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007319 break;
7320 case MPI_EVENT_LOGOUT:
7321 ds = "Logout";
7322 break;
7323 case MPI_EVENT_EVENT_CHANGE:
7324 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06007325 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007326 else
Eric Moore4f766dc2006-07-11 17:24:07 -06007327 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007328 break;
7329 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007330 {
7331 u8 ReasonCode = (u8)(evData0 >> 16);
7332 switch (ReasonCode) {
7333 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
7334 ds = "Integrated Raid: Volume Created";
7335 break;
7336 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
7337 ds = "Integrated Raid: Volume Deleted";
7338 break;
7339 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
7340 ds = "Integrated Raid: Volume Settings Changed";
7341 break;
7342 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
7343 ds = "Integrated Raid: Volume Status Changed";
7344 break;
7345 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
7346 ds = "Integrated Raid: Volume Physdisk Changed";
7347 break;
7348 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
7349 ds = "Integrated Raid: Physdisk Created";
7350 break;
7351 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
7352 ds = "Integrated Raid: Physdisk Deleted";
7353 break;
7354 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
7355 ds = "Integrated Raid: Physdisk Settings Changed";
7356 break;
7357 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
7358 ds = "Integrated Raid: Physdisk Status Changed";
7359 break;
7360 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
7361 ds = "Integrated Raid: Domain Validation Needed";
7362 break;
7363 case MPI_EVENT_RAID_RC_SMART_DATA :
7364 ds = "Integrated Raid; Smart Data";
7365 break;
7366 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
7367 ds = "Integrated Raid: Replace Action Started";
7368 break;
7369 default:
7370 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007371 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007372 }
7373 break;
7374 }
7375 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
7376 ds = "SCSI Device Status Change";
7377 break;
7378 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
7379 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007380 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007381 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007382 u8 ReasonCode = (u8)(evData0 >> 16);
7383 switch (ReasonCode) {
7384 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007385 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007386 "SAS Device Status Change: Added: "
7387 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007388 break;
7389 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06007390 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007391 "SAS Device Status Change: Deleted: "
7392 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007393 break;
7394 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06007395 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007396 "SAS Device Status Change: SMART Data: "
7397 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007398 break;
7399 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007400 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007401 "SAS Device Status Change: No Persistancy: "
7402 "id=%d channel=%d", id, channel);
7403 break;
7404 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
7405 snprintf(evStr, EVENT_DESCR_STR_SZ,
7406 "SAS Device Status Change: Unsupported Device "
7407 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007408 break;
7409 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
7410 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007411 "SAS Device Status Change: Internal Device "
7412 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007413 break;
7414 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
7415 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007416 "SAS Device Status Change: Internal Task "
7417 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007418 break;
7419 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
7420 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007421 "SAS Device Status Change: Internal Abort "
7422 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007423 break;
7424 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
7425 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007426 "SAS Device Status Change: Internal Clear "
7427 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007428 break;
7429 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
7430 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007431 "SAS Device Status Change: Internal Query "
7432 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007433 break;
7434 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007435 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007436 "SAS Device Status Change: Unknown: "
7437 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06007438 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007439 }
7440 break;
7441 }
7442 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
7443 ds = "Bus Timer Expired";
7444 break;
7445 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07007446 {
7447 u16 curr_depth = (u16)(evData0 >> 16);
7448 u8 channel = (u8)(evData0 >> 8);
7449 u8 id = (u8)(evData0);
7450
7451 snprintf(evStr, EVENT_DESCR_STR_SZ,
7452 "Queue Full: channel=%d id=%d depth=%d",
7453 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007454 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07007455 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007456 case MPI_EVENT_SAS_SES:
7457 ds = "SAS SES Event";
7458 break;
7459 case MPI_EVENT_PERSISTENT_TABLE_FULL:
7460 ds = "Persistent Table Full";
7461 break;
7462 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07007463 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007464 u8 LinkRates = (u8)(evData0 >> 8);
7465 u8 PhyNumber = (u8)(evData0);
7466 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
7467 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
7468 switch (LinkRates) {
7469 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06007470 snprintf(evStr, EVENT_DESCR_STR_SZ,
7471 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007472 " Rate Unknown",PhyNumber);
7473 break;
7474 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06007475 snprintf(evStr, EVENT_DESCR_STR_SZ,
7476 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007477 " Phy Disabled",PhyNumber);
7478 break;
7479 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06007480 snprintf(evStr, EVENT_DESCR_STR_SZ,
7481 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007482 " Failed Speed Nego",PhyNumber);
7483 break;
7484 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06007485 snprintf(evStr, EVENT_DESCR_STR_SZ,
7486 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007487 " Sata OOB Completed",PhyNumber);
7488 break;
7489 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06007490 snprintf(evStr, EVENT_DESCR_STR_SZ,
7491 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007492 " Rate 1.5 Gbps",PhyNumber);
7493 break;
7494 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06007495 snprintf(evStr, EVENT_DESCR_STR_SZ,
7496 "SAS PHY Link Status: Phy=%d:"
Kashyap, Desaid75733d2011-02-10 11:50:39 +05307497 " Rate 3.0 Gbps", PhyNumber);
7498 break;
7499 case MPI_EVENT_SAS_PLS_LR_RATE_6_0:
7500 snprintf(evStr, EVENT_DESCR_STR_SZ,
7501 "SAS PHY Link Status: Phy=%d:"
7502 " Rate 6.0 Gbps", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007503 break;
7504 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007505 snprintf(evStr, EVENT_DESCR_STR_SZ,
7506 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007507 break;
7508 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007509 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007510 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007511 case MPI_EVENT_SAS_DISCOVERY_ERROR:
7512 ds = "SAS Discovery Error";
7513 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007514 case MPI_EVENT_IR_RESYNC_UPDATE:
7515 {
7516 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06007517 snprintf(evStr, EVENT_DESCR_STR_SZ,
7518 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07007519 break;
7520 }
7521 case MPI_EVENT_IR2:
7522 {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307523 u8 id = (u8)(evData0);
7524 u8 channel = (u8)(evData0 >> 8);
7525 u8 phys_num = (u8)(evData0 >> 24);
Moore, Eric3a892be2006-03-14 09:14:03 -07007526 u8 ReasonCode = (u8)(evData0 >> 16);
Kashyap, Desai2f187862009-05-29 16:52:37 +05307527
Moore, Eric3a892be2006-03-14 09:14:03 -07007528 switch (ReasonCode) {
7529 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307530 snprintf(evStr, EVENT_DESCR_STR_SZ,
7531 "IR2: LD State Changed: "
7532 "id=%d channel=%d phys_num=%d",
7533 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007534 break;
7535 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307536 snprintf(evStr, EVENT_DESCR_STR_SZ,
7537 "IR2: PD State Changed "
7538 "id=%d channel=%d phys_num=%d",
7539 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007540 break;
7541 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307542 snprintf(evStr, EVENT_DESCR_STR_SZ,
7543 "IR2: Bad Block Table Full: "
7544 "id=%d channel=%d phys_num=%d",
7545 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007546 break;
7547 case MPI_EVENT_IR2_RC_PD_INSERTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307548 snprintf(evStr, EVENT_DESCR_STR_SZ,
7549 "IR2: PD Inserted: "
7550 "id=%d channel=%d phys_num=%d",
7551 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007552 break;
7553 case MPI_EVENT_IR2_RC_PD_REMOVED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307554 snprintf(evStr, EVENT_DESCR_STR_SZ,
7555 "IR2: PD Removed: "
7556 "id=%d channel=%d phys_num=%d",
7557 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007558 break;
7559 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307560 snprintf(evStr, EVENT_DESCR_STR_SZ,
7561 "IR2: Foreign CFG Detected: "
7562 "id=%d channel=%d phys_num=%d",
7563 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007564 break;
7565 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307566 snprintf(evStr, EVENT_DESCR_STR_SZ,
7567 "IR2: Rebuild Medium Error: "
7568 "id=%d channel=%d phys_num=%d",
7569 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007570 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05307571 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
7572 snprintf(evStr, EVENT_DESCR_STR_SZ,
7573 "IR2: Dual Port Added: "
7574 "id=%d channel=%d phys_num=%d",
7575 id, channel, phys_num);
7576 break;
7577 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
7578 snprintf(evStr, EVENT_DESCR_STR_SZ,
7579 "IR2: Dual Port Removed: "
7580 "id=%d channel=%d phys_num=%d",
7581 id, channel, phys_num);
7582 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007583 default:
7584 ds = "IR2";
7585 break;
7586 }
7587 break;
7588 }
7589 case MPI_EVENT_SAS_DISCOVERY:
7590 {
7591 if (evData0)
7592 ds = "SAS Discovery: Start";
7593 else
7594 ds = "SAS Discovery: Stop";
7595 break;
7596 }
7597 case MPI_EVENT_LOG_ENTRY_ADDED:
7598 ds = "SAS Log Entry Added";
7599 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007600
Eric Moorec6c727a2007-01-29 09:44:54 -07007601 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
7602 {
7603 u8 phy_num = (u8)(evData0);
7604 u8 port_num = (u8)(evData0 >> 8);
7605 u8 port_width = (u8)(evData0 >> 16);
7606 u8 primative = (u8)(evData0 >> 24);
7607 snprintf(evStr, EVENT_DESCR_STR_SZ,
7608 "SAS Broadcase Primative: phy=%d port=%d "
7609 "width=%d primative=0x%02x",
7610 phy_num, port_num, port_width, primative);
7611 break;
7612 }
7613
7614 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7615 {
7616 u8 reason = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007617
Kashyap, Desai2f187862009-05-29 16:52:37 +05307618 switch (reason) {
7619 case MPI_EVENT_SAS_INIT_RC_ADDED:
7620 ds = "SAS Initiator Status Change: Added";
7621 break;
7622 case MPI_EVENT_SAS_INIT_RC_REMOVED:
7623 ds = "SAS Initiator Status Change: Deleted";
7624 break;
7625 default:
7626 ds = "SAS Initiator Status Change";
7627 break;
7628 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007629 break;
7630 }
7631
7632 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7633 {
7634 u8 max_init = (u8)(evData0);
7635 u8 current_init = (u8)(evData0 >> 8);
7636
7637 snprintf(evStr, EVENT_DESCR_STR_SZ,
7638 "SAS Initiator Device Table Overflow: max initiators=%02d "
7639 "current initators=%02d",
7640 max_init, current_init);
7641 break;
7642 }
7643 case MPI_EVENT_SAS_SMP_ERROR:
7644 {
7645 u8 status = (u8)(evData0);
7646 u8 port_num = (u8)(evData0 >> 8);
7647 u8 result = (u8)(evData0 >> 16);
7648
7649 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7650 snprintf(evStr, EVENT_DESCR_STR_SZ,
7651 "SAS SMP Error: port=%d result=0x%02x",
7652 port_num, result);
7653 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7654 snprintf(evStr, EVENT_DESCR_STR_SZ,
7655 "SAS SMP Error: port=%d : CRC Error",
7656 port_num);
7657 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7658 snprintf(evStr, EVENT_DESCR_STR_SZ,
7659 "SAS SMP Error: port=%d : Timeout",
7660 port_num);
7661 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7662 snprintf(evStr, EVENT_DESCR_STR_SZ,
7663 "SAS SMP Error: port=%d : No Destination",
7664 port_num);
7665 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7666 snprintf(evStr, EVENT_DESCR_STR_SZ,
7667 "SAS SMP Error: port=%d : Bad Destination",
7668 port_num);
7669 else
7670 snprintf(evStr, EVENT_DESCR_STR_SZ,
7671 "SAS SMP Error: port=%d : status=0x%02x",
7672 port_num, status);
7673 break;
7674 }
7675
Kashyap, Desai2f187862009-05-29 16:52:37 +05307676 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
7677 {
7678 u8 reason = (u8)(evData0);
7679
7680 switch (reason) {
7681 case MPI_EVENT_SAS_EXP_RC_ADDED:
7682 ds = "Expander Status Change: Added";
7683 break;
7684 case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
7685 ds = "Expander Status Change: Deleted";
7686 break;
7687 default:
7688 ds = "Expander Status Change";
7689 break;
7690 }
7691 break;
7692 }
7693
Linus Torvalds1da177e2005-04-16 15:20:36 -07007694 /*
7695 * MPT base "custom" events may be added here...
7696 */
7697 default:
7698 ds = "Unknown";
7699 break;
7700 }
Eric Moore509e5e52006-04-26 13:22:37 -06007701 if (ds)
7702 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007703
Kashyap, Desai2f187862009-05-29 16:52:37 +05307704
7705 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7706 "MPT event:(%02Xh) : %s\n",
7707 ioc->name, event, evStr));
7708
7709 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
7710 ": Event data:\n"));
7711 for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
7712 devtverboseprintk(ioc, printk(" %08x",
7713 le32_to_cpu(pEventReply->Data[ii])));
7714 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
7715}
7716#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007717/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007718/**
7719 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007720 * @ioc: Pointer to MPT_ADAPTER structure
7721 * @pEventReply: Pointer to EventNotification reply frame
7722 * @evHandlers: Pointer to integer, number of event handlers
7723 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007724 * Routes a received EventNotificationReply to all currently registered
7725 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007726 * Returns sum of event handlers return values.
7727 */
7728static int
7729ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7730{
7731 u16 evDataLen;
7732 u32 evData0 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007733 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307734 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007735 int r = 0;
7736 int handlers = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007737 u8 event;
7738
7739 /*
7740 * Do platform normalization of values
7741 */
7742 event = le32_to_cpu(pEventReply->Event) & 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007743 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7744 if (evDataLen) {
7745 evData0 = le32_to_cpu(pEventReply->Data[0]);
7746 }
7747
Prakash, Sathya436ace72007-07-24 15:42:08 +05307748#ifdef CONFIG_FUSION_LOGGING
Kashyap, Desai2f187862009-05-29 16:52:37 +05307749 if (evDataLen)
7750 mpt_display_event_info(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007751#endif
7752
7753 /*
7754 * Do general / base driver event processing
7755 */
7756 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007757 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7758 if (evDataLen) {
7759 u8 evState = evData0 & 0xFF;
7760
7761 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7762
7763 /* Update EventState field in cached IocFacts */
7764 if (ioc->facts.Function) {
7765 ioc->facts.EventState = evState;
7766 }
7767 }
7768 break;
Moore, Ericece50912006-01-16 18:53:19 -07007769 case MPI_EVENT_INTEGRATED_RAID:
7770 mptbase_raid_process_event_data(ioc,
7771 (MpiEventDataRaid_t *)pEventReply->Data);
7772 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007773 default:
7774 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007775 }
7776
7777 /*
7778 * Should this event be logged? Events are written sequentially.
7779 * When buffer is full, start again at the top.
7780 */
7781 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7782 int idx;
7783
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007784 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007785
7786 ioc->events[idx].event = event;
7787 ioc->events[idx].eventContext = ioc->eventContext;
7788
7789 for (ii = 0; ii < 2; ii++) {
7790 if (ii < evDataLen)
7791 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7792 else
7793 ioc->events[idx].data[ii] = 0;
7794 }
7795
7796 ioc->eventContext++;
7797 }
7798
7799
7800 /*
7801 * Call each currently registered protocol event handler.
7802 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007803 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307804 if (MptEvHandlers[cb_idx]) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307805 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7806 "Routing Event to event handler #%d\n",
7807 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307808 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007809 handlers++;
7810 }
7811 }
7812 /* FIXME? Examine results here? */
7813
7814 /*
7815 * If needed, send (a single) EventAck.
7816 */
7817 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307818 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007819 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007820 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307821 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007822 ioc->name, ii));
7823 }
7824 }
7825
7826 *evHandlers = handlers;
7827 return r;
7828}
7829
7830/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007831/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007832 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7833 * @ioc: Pointer to MPT_ADAPTER structure
7834 * @log_info: U32 LogInfo reply word from the IOC
7835 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007836 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007837 */
7838static void
7839mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7840{
Eric Moore7c431e52007-06-13 16:34:36 -06007841 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007842
Eric Moore7c431e52007-06-13 16:34:36 -06007843 switch (log_info & 0xFF000000) {
7844 case MPI_IOCLOGINFO_FC_INIT_BASE:
7845 desc = "FCP Initiator";
7846 break;
7847 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7848 desc = "FCP Target";
7849 break;
7850 case MPI_IOCLOGINFO_FC_LAN_BASE:
7851 desc = "LAN";
7852 break;
7853 case MPI_IOCLOGINFO_FC_MSG_BASE:
7854 desc = "MPI Message Layer";
7855 break;
7856 case MPI_IOCLOGINFO_FC_LINK_BASE:
7857 desc = "FC Link";
7858 break;
7859 case MPI_IOCLOGINFO_FC_CTX_BASE:
7860 desc = "Context Manager";
7861 break;
7862 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7863 desc = "Invalid Field Offset";
7864 break;
7865 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7866 desc = "State Change Info";
7867 break;
7868 }
7869
7870 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7871 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007872}
7873
7874/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007875/**
Moore, Eric335a9412006-01-17 17:06:23 -07007876 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007877 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007878 * @log_info: U32 LogInfo word from the IOC
7879 *
7880 * Refer to lsi/sp_log.h.
7881 */
7882static void
Moore, Eric335a9412006-01-17 17:06:23 -07007883mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007884{
7885 u32 info = log_info & 0x00FF0000;
7886 char *desc = "unknown";
7887
7888 switch (info) {
7889 case 0x00010000:
7890 desc = "bug! MID not found";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007891 break;
7892
7893 case 0x00020000:
7894 desc = "Parity Error";
7895 break;
7896
7897 case 0x00030000:
7898 desc = "ASYNC Outbound Overrun";
7899 break;
7900
7901 case 0x00040000:
7902 desc = "SYNC Offset Error";
7903 break;
7904
7905 case 0x00050000:
7906 desc = "BM Change";
7907 break;
7908
7909 case 0x00060000:
7910 desc = "Msg In Overflow";
7911 break;
7912
7913 case 0x00070000:
7914 desc = "DMA Error";
7915 break;
7916
7917 case 0x00080000:
7918 desc = "Outbound DMA Overrun";
7919 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007920
Linus Torvalds1da177e2005-04-16 15:20:36 -07007921 case 0x00090000:
7922 desc = "Task Management";
7923 break;
7924
7925 case 0x000A0000:
7926 desc = "Device Problem";
7927 break;
7928
7929 case 0x000B0000:
7930 desc = "Invalid Phase Change";
7931 break;
7932
7933 case 0x000C0000:
7934 desc = "Untagged Table Size";
7935 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007936
Linus Torvalds1da177e2005-04-16 15:20:36 -07007937 }
7938
7939 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7940}
7941
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007942/* strings for sas loginfo */
7943 static char *originator_str[] = {
7944 "IOP", /* 00h */
7945 "PL", /* 01h */
7946 "IR" /* 02h */
7947 };
7948 static char *iop_code_str[] = {
7949 NULL, /* 00h */
7950 "Invalid SAS Address", /* 01h */
7951 NULL, /* 02h */
7952 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007953 "Diag Message Error", /* 04h */
7954 "Task Terminated", /* 05h */
7955 "Enclosure Management", /* 06h */
7956 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007957 };
7958 static char *pl_code_str[] = {
7959 NULL, /* 00h */
7960 "Open Failure", /* 01h */
7961 "Invalid Scatter Gather List", /* 02h */
7962 "Wrong Relative Offset or Frame Length", /* 03h */
7963 "Frame Transfer Error", /* 04h */
7964 "Transmit Frame Connected Low", /* 05h */
7965 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7966 "SATA Read Log Receive Data Error", /* 07h */
7967 "SATA NCQ Fail All Commands After Error", /* 08h */
7968 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7969 "Receive Frame Invalid Message", /* 0Ah */
7970 "Receive Context Message Valid Error", /* 0Bh */
7971 "Receive Frame Current Frame Error", /* 0Ch */
7972 "SATA Link Down", /* 0Dh */
7973 "Discovery SATA Init W IOS", /* 0Eh */
7974 "Config Invalid Page", /* 0Fh */
7975 "Discovery SATA Init Timeout", /* 10h */
7976 "Reset", /* 11h */
7977 "Abort", /* 12h */
7978 "IO Not Yet Executed", /* 13h */
7979 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007980 "Persistent Reservation Out Not Affiliation "
7981 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007982 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007983 "IO Device Missing Delay Retry", /* 17h */
Lucas De Marchi25985ed2011-03-30 22:57:33 -03007984 "IO Cancelled Due to Receive Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007985 NULL, /* 19h */
7986 NULL, /* 1Ah */
7987 NULL, /* 1Bh */
7988 NULL, /* 1Ch */
7989 NULL, /* 1Dh */
7990 NULL, /* 1Eh */
7991 NULL, /* 1Fh */
7992 "Enclosure Management" /* 20h */
7993 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007994 static char *ir_code_str[] = {
7995 "Raid Action Error", /* 00h */
7996 NULL, /* 00h */
7997 NULL, /* 01h */
7998 NULL, /* 02h */
7999 NULL, /* 03h */
8000 NULL, /* 04h */
8001 NULL, /* 05h */
8002 NULL, /* 06h */
8003 NULL /* 07h */
8004 };
8005 static char *raid_sub_code_str[] = {
8006 NULL, /* 00h */
8007 "Volume Creation Failed: Data Passed too "
8008 "Large", /* 01h */
8009 "Volume Creation Failed: Duplicate Volumes "
8010 "Attempted", /* 02h */
8011 "Volume Creation Failed: Max Number "
8012 "Supported Volumes Exceeded", /* 03h */
8013 "Volume Creation Failed: DMA Error", /* 04h */
8014 "Volume Creation Failed: Invalid Volume Type", /* 05h */
8015 "Volume Creation Failed: Error Reading "
8016 "MFG Page 4", /* 06h */
8017 "Volume Creation Failed: Creating Internal "
8018 "Structures", /* 07h */
8019 NULL, /* 08h */
8020 NULL, /* 09h */
8021 NULL, /* 0Ah */
8022 NULL, /* 0Bh */
8023 NULL, /* 0Ch */
8024 NULL, /* 0Dh */
8025 NULL, /* 0Eh */
8026 NULL, /* 0Fh */
8027 "Activation failed: Already Active Volume", /* 10h */
8028 "Activation failed: Unsupported Volume Type", /* 11h */
8029 "Activation failed: Too Many Active Volumes", /* 12h */
8030 "Activation failed: Volume ID in Use", /* 13h */
8031 "Activation failed: Reported Failure", /* 14h */
8032 "Activation failed: Importing a Volume", /* 15h */
8033 NULL, /* 16h */
8034 NULL, /* 17h */
8035 NULL, /* 18h */
8036 NULL, /* 19h */
8037 NULL, /* 1Ah */
8038 NULL, /* 1Bh */
8039 NULL, /* 1Ch */
8040 NULL, /* 1Dh */
8041 NULL, /* 1Eh */
8042 NULL, /* 1Fh */
8043 "Phys Disk failed: Too Many Phys Disks", /* 20h */
8044 "Phys Disk failed: Data Passed too Large", /* 21h */
8045 "Phys Disk failed: DMA Error", /* 22h */
8046 "Phys Disk failed: Invalid <channel:id>", /* 23h */
8047 "Phys Disk failed: Creating Phys Disk Config "
8048 "Page", /* 24h */
8049 NULL, /* 25h */
8050 NULL, /* 26h */
8051 NULL, /* 27h */
8052 NULL, /* 28h */
8053 NULL, /* 29h */
8054 NULL, /* 2Ah */
8055 NULL, /* 2Bh */
8056 NULL, /* 2Ch */
8057 NULL, /* 2Dh */
8058 NULL, /* 2Eh */
8059 NULL, /* 2Fh */
8060 "Compatibility Error: IR Disabled", /* 30h */
Uwe Kleine-Königb5950762010-11-01 15:38:34 -04008061 "Compatibility Error: Inquiry Command Failed", /* 31h */
Eric Moorec6c727a2007-01-29 09:44:54 -07008062 "Compatibility Error: Device not Direct Access "
8063 "Device ", /* 32h */
8064 "Compatibility Error: Removable Device Found", /* 33h */
8065 "Compatibility Error: Device SCSI Version not "
8066 "2 or Higher", /* 34h */
8067 "Compatibility Error: SATA Device, 48 BIT LBA "
8068 "not Supported", /* 35h */
8069 "Compatibility Error: Device doesn't have "
8070 "512 Byte Block Sizes", /* 36h */
8071 "Compatibility Error: Volume Type Check Failed", /* 37h */
8072 "Compatibility Error: Volume Type is "
8073 "Unsupported by FW", /* 38h */
8074 "Compatibility Error: Disk Drive too Small for "
8075 "use in Volume", /* 39h */
8076 "Compatibility Error: Phys Disk for Create "
8077 "Volume not Found", /* 3Ah */
8078 "Compatibility Error: Too Many or too Few "
8079 "Disks for Volume Type", /* 3Bh */
8080 "Compatibility Error: Disk stripe Sizes "
8081 "Must be 64KB", /* 3Ch */
8082 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
8083 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008084
8085/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008086/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008087 * mpt_sas_log_info - Log information returned from SAS IOC.
8088 * @ioc: Pointer to MPT_ADAPTER structure
8089 * @log_info: U32 LogInfo reply word from the IOC
Randy Dunlapfc58fb12010-08-14 13:05:57 -07008090 * @cb_idx: callback function's handle
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008091 *
8092 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008093 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008094static void
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308095mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info, u8 cb_idx)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008096{
8097union loginfo_type {
8098 u32 loginfo;
8099 struct {
8100 u32 subcode:16;
8101 u32 code:8;
8102 u32 originator:4;
8103 u32 bus_type:4;
8104 }dw;
8105};
8106 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07008107 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008108 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07008109 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008110
8111 sas_loginfo.loginfo = log_info;
8112 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008113 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008114 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07008115
8116 originator_desc = originator_str[sas_loginfo.dw.originator];
8117
8118 switch (sas_loginfo.dw.originator) {
8119
8120 case 0: /* IOP */
8121 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008122 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008123 code_desc = iop_code_str[sas_loginfo.dw.code];
8124 break;
8125 case 1: /* PL */
8126 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008127 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008128 code_desc = pl_code_str[sas_loginfo.dw.code];
8129 break;
8130 case 2: /* IR */
8131 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008132 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008133 break;
8134 code_desc = ir_code_str[sas_loginfo.dw.code];
8135 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008136 ARRAY_SIZE(raid_sub_code_str))
Julia Lawall081f4f42010-08-05 22:27:14 +02008137 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07008138 if (sas_loginfo.dw.code == 0)
8139 sub_code_desc =
8140 raid_sub_code_str[sas_loginfo.dw.subcode];
8141 break;
8142 default:
8143 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008144 }
8145
Eric Moorec6c727a2007-01-29 09:44:54 -07008146 if (sub_code_desc != NULL)
8147 printk(MYIOC_s_INFO_FMT
8148 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308149 " SubCode={%s} cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008150 ioc->name, log_info, originator_desc, code_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308151 sub_code_desc, MptCallbacksName[cb_idx]);
Eric Moorec6c727a2007-01-29 09:44:54 -07008152 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008153 printk(MYIOC_s_INFO_FMT
8154 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308155 " SubCode(0x%04x) cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008156 ioc->name, log_info, originator_desc, code_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308157 sas_loginfo.dw.subcode, MptCallbacksName[cb_idx]);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008158 else
8159 printk(MYIOC_s_INFO_FMT
8160 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308161 " SubCode(0x%04x) cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008162 ioc->name, log_info, originator_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308163 sas_loginfo.dw.code, sas_loginfo.dw.subcode,
8164 MptCallbacksName[cb_idx]);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008165}
8166
Linus Torvalds1da177e2005-04-16 15:20:36 -07008167/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008168/**
Eric Moorec6c727a2007-01-29 09:44:54 -07008169 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
8170 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08008171 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07008172 * @mf: Pointer to MPT request frame
8173 *
8174 * Refer to lsi/mpi.h.
8175 **/
8176static void
8177mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
8178{
8179 Config_t *pReq = (Config_t *)mf;
8180 char extend_desc[EVENT_DESCR_STR_SZ];
8181 char *desc = NULL;
8182 u32 form;
8183 u8 page_type;
8184
8185 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
8186 page_type = pReq->ExtPageType;
8187 else
8188 page_type = pReq->Header.PageType;
8189
8190 /*
8191 * ignore invalid page messages for GET_NEXT_HANDLE
8192 */
8193 form = le32_to_cpu(pReq->PageAddress);
8194 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
8195 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
8196 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
8197 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
8198 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
8199 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
8200 return;
8201 }
8202 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
8203 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
8204 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
8205 return;
8206 }
8207
8208 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
8209 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
8210 page_type, pReq->Header.PageNumber, pReq->Action, form);
8211
8212 switch (ioc_status) {
8213
8214 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8215 desc = "Config Page Invalid Action";
8216 break;
8217
8218 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8219 desc = "Config Page Invalid Type";
8220 break;
8221
8222 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8223 desc = "Config Page Invalid Page";
8224 break;
8225
8226 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8227 desc = "Config Page Invalid Data";
8228 break;
8229
8230 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8231 desc = "Config Page No Defaults";
8232 break;
8233
8234 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
8235 desc = "Config Page Can't Commit";
8236 break;
8237 }
8238
8239 if (!desc)
8240 return;
8241
Eric Moore29dd3602007-09-14 18:46:51 -06008242 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
8243 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07008244}
8245
8246/**
8247 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07008248 * @ioc: Pointer to MPT_ADAPTER structure
8249 * @ioc_status: U32 IOCStatus word from IOC
8250 * @mf: Pointer to MPT request frame
8251 *
8252 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008253 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07008254static void
Eric Moorec6c727a2007-01-29 09:44:54 -07008255mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008256{
8257 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06008258 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008259
8260 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07008261
8262/****************************************************************************/
8263/* Common IOCStatus values for all replies */
8264/****************************************************************************/
8265
Linus Torvalds1da177e2005-04-16 15:20:36 -07008266 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
8267 desc = "Invalid Function";
8268 break;
8269
8270 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
8271 desc = "Busy";
8272 break;
8273
8274 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
8275 desc = "Invalid SGL";
8276 break;
8277
8278 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
8279 desc = "Internal Error";
8280 break;
8281
8282 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
8283 desc = "Reserved";
8284 break;
8285
8286 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
8287 desc = "Insufficient Resources";
8288 break;
8289
8290 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
8291 desc = "Invalid Field";
8292 break;
8293
8294 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
8295 desc = "Invalid State";
8296 break;
8297
Eric Moorec6c727a2007-01-29 09:44:54 -07008298/****************************************************************************/
8299/* Config IOCStatus values */
8300/****************************************************************************/
8301
Linus Torvalds1da177e2005-04-16 15:20:36 -07008302 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8303 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8304 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8305 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8306 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8307 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008308 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008309 break;
8310
Eric Moorec6c727a2007-01-29 09:44:54 -07008311/****************************************************************************/
8312/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
8313/* */
8314/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
8315/* */
8316/****************************************************************************/
8317
Linus Torvalds1da177e2005-04-16 15:20:36 -07008318 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008319 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008320 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
8321 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
8322 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
8323 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008324 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008325 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008326 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008327 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008328 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008329 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07008330 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008331 break;
8332
Eric Moorec6c727a2007-01-29 09:44:54 -07008333/****************************************************************************/
8334/* SCSI Target values */
8335/****************************************************************************/
8336
8337 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
8338 desc = "Target: Priority IO";
8339 break;
8340
8341 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
8342 desc = "Target: Invalid Port";
8343 break;
8344
8345 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
8346 desc = "Target Invalid IO Index:";
8347 break;
8348
8349 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
8350 desc = "Target: Aborted";
8351 break;
8352
8353 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
8354 desc = "Target: No Conn Retryable";
8355 break;
8356
8357 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
8358 desc = "Target: No Connection";
8359 break;
8360
8361 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
8362 desc = "Target: Transfer Count Mismatch";
8363 break;
8364
8365 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
8366 desc = "Target: STS Data not Sent";
8367 break;
8368
8369 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
8370 desc = "Target: Data Offset Error";
8371 break;
8372
8373 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
8374 desc = "Target: Too Much Write Data";
8375 break;
8376
8377 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
8378 desc = "Target: IU Too Short";
8379 break;
8380
8381 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
8382 desc = "Target: ACK NAK Timeout";
8383 break;
8384
8385 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
8386 desc = "Target: Nak Received";
8387 break;
8388
8389/****************************************************************************/
8390/* Fibre Channel Direct Access values */
8391/****************************************************************************/
8392
8393 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
8394 desc = "FC: Aborted";
8395 break;
8396
8397 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
8398 desc = "FC: RX ID Invalid";
8399 break;
8400
8401 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
8402 desc = "FC: DID Invalid";
8403 break;
8404
8405 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
8406 desc = "FC: Node Logged Out";
8407 break;
8408
8409 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
8410 desc = "FC: Exchange Canceled";
8411 break;
8412
8413/****************************************************************************/
8414/* LAN values */
8415/****************************************************************************/
8416
8417 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
8418 desc = "LAN: Device not Found";
8419 break;
8420
8421 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
8422 desc = "LAN: Device Failure";
8423 break;
8424
8425 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
8426 desc = "LAN: Transmit Error";
8427 break;
8428
8429 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
8430 desc = "LAN: Transmit Aborted";
8431 break;
8432
8433 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
8434 desc = "LAN: Receive Error";
8435 break;
8436
8437 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
8438 desc = "LAN: Receive Aborted";
8439 break;
8440
8441 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
8442 desc = "LAN: Partial Packet";
8443 break;
8444
8445 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
8446 desc = "LAN: Canceled";
8447 break;
8448
8449/****************************************************************************/
8450/* Serial Attached SCSI values */
8451/****************************************************************************/
8452
8453 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
8454 desc = "SAS: SMP Request Failed";
8455 break;
8456
8457 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
8458 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07008459 break;
8460
8461 default:
8462 desc = "Others";
8463 break;
8464 }
Eric Moorec6c727a2007-01-29 09:44:54 -07008465
8466 if (!desc)
8467 return;
8468
Eric Moore29dd3602007-09-14 18:46:51 -06008469 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
8470 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008471}
8472
8473/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008474EXPORT_SYMBOL(mpt_attach);
8475EXPORT_SYMBOL(mpt_detach);
8476#ifdef CONFIG_PM
8477EXPORT_SYMBOL(mpt_resume);
8478EXPORT_SYMBOL(mpt_suspend);
8479#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07008480EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008481EXPORT_SYMBOL(mpt_register);
8482EXPORT_SYMBOL(mpt_deregister);
8483EXPORT_SYMBOL(mpt_event_register);
8484EXPORT_SYMBOL(mpt_event_deregister);
8485EXPORT_SYMBOL(mpt_reset_register);
8486EXPORT_SYMBOL(mpt_reset_deregister);
8487EXPORT_SYMBOL(mpt_device_driver_register);
8488EXPORT_SYMBOL(mpt_device_driver_deregister);
8489EXPORT_SYMBOL(mpt_get_msg_frame);
8490EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05308491EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008492EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008493EXPORT_SYMBOL(mpt_send_handshake_request);
8494EXPORT_SYMBOL(mpt_verify_adapter);
8495EXPORT_SYMBOL(mpt_GetIocState);
8496EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008497EXPORT_SYMBOL(mpt_HardResetHandler);
8498EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008499EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008500EXPORT_SYMBOL(mpt_alloc_fw_memory);
8501EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02008502EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07008503EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008504
Linus Torvalds1da177e2005-04-16 15:20:36 -07008505/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008506/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008507 * fusion_init - Fusion MPT base driver initialization routine.
8508 *
8509 * Returns 0 for success, non-zero for failure.
8510 */
8511static int __init
8512fusion_init(void)
8513{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308514 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008515
8516 show_mptmod_ver(my_NAME, my_VERSION);
8517 printk(KERN_INFO COPYRIGHT "\n");
8518
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308519 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
8520 MptCallbacks[cb_idx] = NULL;
8521 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
8522 MptEvHandlers[cb_idx] = NULL;
8523 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008524 }
8525
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008526 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07008527 * EventNotification handling.
8528 */
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308529 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER,
8530 "mptbase_reply");
Linus Torvalds1da177e2005-04-16 15:20:36 -07008531
8532 /* Register for hard reset handling callbacks.
8533 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05308534 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008535
8536#ifdef CONFIG_PROC_FS
8537 (void) procmpt_create();
8538#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008539 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008540}
8541
8542/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008543/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008544 * fusion_exit - Perform driver unload cleanup.
8545 *
8546 * This routine frees all resources associated with each MPT adapter
8547 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
8548 */
8549static void __exit
8550fusion_exit(void)
8551{
8552
Linus Torvalds1da177e2005-04-16 15:20:36 -07008553 mpt_reset_deregister(mpt_base_index);
8554
8555#ifdef CONFIG_PROC_FS
8556 procmpt_destroy();
8557#endif
8558}
8559
Linus Torvalds1da177e2005-04-16 15:20:36 -07008560module_init(fusion_init);
8561module_exit(fusion_exit);