blob: a896d948b79ee12b36f82c3d04c6c3ec34d9d1b0 [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
3175 sz = facts->FWImageSize;
3176 if ( sz & 0x01 )
3177 sz += 1;
3178 if ( sz & 0x02 )
3179 sz += 2;
3180 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003181
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 if (!facts->RequestFrameSize) {
3183 /* Something is wrong! */
3184 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3185 ioc->name);
3186 return -55;
3187 }
3188
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003189 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 vv = ((63 / (sz * 4)) + 1) & 0x03;
3191 ioc->NB_for_64_byte_frame = vv;
3192 while ( sz )
3193 {
3194 shiftFactor++;
3195 sz = sz >> 1;
3196 }
3197 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303198 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003199 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3200 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003201
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3203 /*
3204 * Set values for this IOC's request & reply frame sizes,
3205 * and request & reply queue depths...
3206 */
3207 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3208 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3209 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3210 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3211
Prakash, Sathya436ace72007-07-24 15:42:08 +05303212 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303214 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 ioc->name, ioc->req_sz, ioc->req_depth));
3216
3217 /* Get port facts! */
3218 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3219 return r;
3220 }
3221 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003222 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3224 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3225 RequestFrameSize)/sizeof(u32)));
3226 return -66;
3227 }
3228
3229 return 0;
3230}
3231
3232/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003233/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 * GetPortFacts - Send PortFacts request to MPT adapter.
3235 * @ioc: Pointer to MPT_ADAPTER structure
3236 * @portnum: Port number
3237 * @sleepFlag: Specifies whether the process can sleep
3238 *
3239 * Returns 0 for success, non-zero for failure.
3240 */
3241static int
3242GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3243{
3244 PortFacts_t get_pfacts;
3245 PortFactsReply_t *pfacts;
3246 int ii;
3247 int req_sz;
3248 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003249 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250
3251 /* IOC *must* NOT be in RESET state! */
3252 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003253 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3254 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 return -4;
3256 }
3257
3258 pfacts = &ioc->pfacts[portnum];
3259
3260 /* Destination (reply area)... */
3261 reply_sz = sizeof(*pfacts);
3262 memset(pfacts, 0, reply_sz);
3263
3264 /* Request area (get_pfacts on the stack right now!) */
3265 req_sz = sizeof(get_pfacts);
3266 memset(&get_pfacts, 0, req_sz);
3267
3268 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3269 get_pfacts.PortNumber = portnum;
3270 /* Assert: All other get_pfacts fields are zero! */
3271
Prakash, Sathya436ace72007-07-24 15:42:08 +05303272 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 ioc->name, portnum));
3274
3275 /* No non-zero fields in the get_pfacts request are greater than
3276 * 1 byte in size, so we can just fire it off as is.
3277 */
3278 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3279 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3280 if (ii != 0)
3281 return ii;
3282
3283 /* Did we get a valid reply? */
3284
3285 /* Now byte swap the necessary fields in the response. */
3286 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3287 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3288 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3289 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3290 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3291 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3292 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3293 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3294 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3295
Eric Moore793955f2007-01-29 09:42:20 -07003296 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3297 pfacts->MaxDevices;
3298 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3299 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3300
3301 /*
3302 * Place all the devices on channels
3303 *
3304 * (for debuging)
3305 */
3306 if (mpt_channel_mapping) {
3307 ioc->devices_per_bus = 1;
3308 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3309 }
3310
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 return 0;
3312}
3313
3314/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003315/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 * SendIocInit - Send IOCInit request to MPT adapter.
3317 * @ioc: Pointer to MPT_ADAPTER structure
3318 * @sleepFlag: Specifies whether the process can sleep
3319 *
3320 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3321 *
3322 * Returns 0 for success, non-zero for failure.
3323 */
3324static int
3325SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3326{
3327 IOCInit_t ioc_init;
3328 MPIDefaultReply_t init_reply;
3329 u32 state;
3330 int r;
3331 int count;
3332 int cntdn;
3333
3334 memset(&ioc_init, 0, sizeof(ioc_init));
3335 memset(&init_reply, 0, sizeof(init_reply));
3336
3337 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3338 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3339
3340 /* If we are in a recovery mode and we uploaded the FW image,
3341 * then this pointer is not NULL. Skip the upload a second time.
3342 * Set this flag if cached_fw set for either IOC.
3343 */
3344 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3345 ioc->upload_fw = 1;
3346 else
3347 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303348 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3350
Eric Moore793955f2007-01-29 09:42:20 -07003351 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3352 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303353
Prakash, Sathya436ace72007-07-24 15:42:08 +05303354 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003355 ioc->name, ioc->facts.MsgVersion));
3356 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3357 // set MsgVersion and HeaderVersion host driver was built with
3358 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3359 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003361 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3362 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3363 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3364 return -99;
3365 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3367
Kashyap, Desai2f187862009-05-29 16:52:37 +05303368 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 /* Save the upper 32-bits of the request
3370 * (reply) and sense buffers.
3371 */
3372 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3373 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3374 } else {
3375 /* Force 32-bit addressing */
3376 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3377 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3378 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003379
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3381 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003382 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3383 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384
Prakash, Sathya436ace72007-07-24 15:42:08 +05303385 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 ioc->name, &ioc_init));
3387
3388 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3389 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003390 if (r != 0) {
3391 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394
3395 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003396 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 */
3398
Prakash, Sathya436ace72007-07-24 15:42:08 +05303399 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003401
3402 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3403 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406
3407 /* YIKES! SUPER IMPORTANT!!!
3408 * Poll IocState until _OPERATIONAL while IOC is doing
3409 * LoopInit and TargetDiscovery!
3410 */
3411 count = 0;
3412 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3413 state = mpt_GetIocState(ioc, 1);
3414 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3415 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003416 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 } else {
3418 mdelay(1);
3419 }
3420
3421 if (!cntdn) {
3422 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3423 ioc->name, (int)((count+5)/HZ));
3424 return -9;
3425 }
3426
3427 state = mpt_GetIocState(ioc, 1);
3428 count++;
3429 }
Eric Moore29dd3602007-09-14 18:46:51 -06003430 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 ioc->name, count));
3432
Eric Mooreba856d32006-07-11 17:34:01 -06003433 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 return r;
3435}
3436
3437/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003438/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 * SendPortEnable - Send PortEnable request to MPT adapter port.
3440 * @ioc: Pointer to MPT_ADAPTER structure
3441 * @portnum: Port number to enable
3442 * @sleepFlag: Specifies whether the process can sleep
3443 *
3444 * Send PortEnable to bring IOC to OPERATIONAL state.
3445 *
3446 * Returns 0 for success, non-zero for failure.
3447 */
3448static int
3449SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3450{
3451 PortEnable_t port_enable;
3452 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003453 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 int req_sz;
3455 int reply_sz;
3456
3457 /* Destination... */
3458 reply_sz = sizeof(MPIDefaultReply_t);
3459 memset(&reply_buf, 0, reply_sz);
3460
3461 req_sz = sizeof(PortEnable_t);
3462 memset(&port_enable, 0, req_sz);
3463
3464 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3465 port_enable.PortNumber = portnum;
3466/* port_enable.ChainOffset = 0; */
3467/* port_enable.MsgFlags = 0; */
3468/* port_enable.MsgContext = 0; */
3469
Prakash, Sathya436ace72007-07-24 15:42:08 +05303470 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 ioc->name, portnum, &port_enable));
3472
3473 /* RAID FW may take a long time to enable
3474 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003475 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003476 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3477 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3478 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003479 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003480 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3481 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3482 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003484 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485}
3486
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003487/**
3488 * mpt_alloc_fw_memory - allocate firmware memory
3489 * @ioc: Pointer to MPT_ADAPTER structure
3490 * @size: total FW bytes
3491 *
3492 * If memory has already been allocated, the same (cached) value
3493 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303494 *
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003495 * Return 0 if successful, or non-zero for failure
Prakash, Sathya984621b2008-01-11 14:42:17 +05303496 **/
3497int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3499{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303500 int rc;
3501
3502 if (ioc->cached_fw) {
3503 rc = 0; /* use already allocated memory */
3504 goto out;
3505 }
3506 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3508 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303509 rc = 0;
3510 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303512 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3513 if (!ioc->cached_fw) {
3514 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3515 ioc->name);
3516 rc = -1;
3517 } else {
3518 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3519 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3520 ioc->alloc_total += size;
3521 rc = 0;
3522 }
3523 out:
3524 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303526
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003527/**
3528 * mpt_free_fw_memory - free firmware memory
3529 * @ioc: Pointer to MPT_ADAPTER structure
3530 *
3531 * If alt_img is NULL, delete from ioc structure.
3532 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303533 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534void
3535mpt_free_fw_memory(MPT_ADAPTER *ioc)
3536{
3537 int sz;
3538
Prakash, Sathya984621b2008-01-11 14:42:17 +05303539 if (!ioc->cached_fw)
3540 return;
3541
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303543 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3544 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003545 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303546 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548}
3549
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003551/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3553 * @ioc: Pointer to MPT_ADAPTER structure
3554 * @sleepFlag: Specifies whether the process can sleep
3555 *
3556 * Returns 0 for success, >0 for handshake failure
3557 * <0 for fw upload failure.
3558 *
3559 * Remark: If bound IOC and a successful FWUpload was performed
3560 * on the bound IOC, the second image is discarded
3561 * and memory is free'd. Both channels must upload to prevent
3562 * IOC from running in degraded mode.
3563 */
3564static int
3565mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3566{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567 u8 reply[sizeof(FWUploadReply_t)];
3568 FWUpload_t *prequest;
3569 FWUploadReply_t *preply;
3570 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571 u32 flagsLength;
3572 int ii, sz, reply_sz;
3573 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303574 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575 /* If the image size is 0, we are done.
3576 */
3577 if ((sz = ioc->facts.FWImageSize) == 0)
3578 return 0;
3579
Prakash, Sathya984621b2008-01-11 14:42:17 +05303580 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3581 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582
Eric Moore29dd3602007-09-14 18:46:51 -06003583 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3584 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003585
Eric Moorebc6e0892007-09-29 10:16:28 -06003586 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3587 kzalloc(ioc->req_sz, GFP_KERNEL);
3588 if (!prequest) {
3589 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3590 "while allocating memory \n", ioc->name));
3591 mpt_free_fw_memory(ioc);
3592 return -ENOMEM;
3593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594
Eric Moorebc6e0892007-09-29 10:16:28 -06003595 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596
3597 reply_sz = sizeof(reply);
3598 memset(preply, 0, reply_sz);
3599
3600 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3601 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3602
3603 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3604 ptcsge->DetailsLength = 12;
3605 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3606 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003607 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303610 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3611 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3612 ioc->SGE_size;
3613 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3614 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3615 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003616 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303618 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3619 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620
Kashyap, Desai2f187862009-05-29 16:52:37 +05303621 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
3622 "rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623
3624 cmdStatus = -EFAULT;
3625 if (ii == 0) {
3626 /* Handshake transfer was complete and successful.
3627 * Check the Reply Frame.
3628 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303629 int status;
3630 status = le16_to_cpu(preply->IOCStatus) &
3631 MPI_IOCSTATUS_MASK;
3632 if (status == MPI_IOCSTATUS_SUCCESS &&
3633 ioc->facts.FWImageSize ==
3634 le32_to_cpu(preply->ActualImageSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 cmdStatus = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303637 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 ioc->name, cmdStatus));
3639
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003640
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 if (cmdStatus) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303642 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
3643 "freeing image \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644 mpt_free_fw_memory(ioc);
3645 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003646 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647
3648 return cmdStatus;
3649}
3650
3651/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003652/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 * mpt_downloadboot - DownloadBoot code
3654 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003655 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656 * @sleepFlag: Specifies whether the process can sleep
3657 *
3658 * FwDownloadBoot requires Programmed IO access.
3659 *
3660 * Returns 0 for success
3661 * -1 FW Image size is 0
3662 * -2 No valid cached_fw Pointer
3663 * <0 for fw upload failure.
3664 */
3665static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003666mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 MpiExtImageHeader_t *pExtImage;
3669 u32 fwSize;
3670 u32 diag0val;
3671 int count;
3672 u32 *ptrFw;
3673 u32 diagRwData;
3674 u32 nextImage;
3675 u32 load_addr;
3676 u32 ioc_state=0;
3677
Prakash, Sathya436ace72007-07-24 15:42:08 +05303678 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003679 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003680
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3682 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3683 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3684 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3685 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3686 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3687
3688 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3689
3690 /* wait 1 msec */
3691 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003692 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 } else {
3694 mdelay (1);
3695 }
3696
3697 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3698 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3699
3700 for (count = 0; count < 30; count ++) {
3701 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3702 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303703 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 ioc->name, count));
3705 break;
3706 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003707 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003709 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003711 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 }
3713 }
3714
3715 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303716 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003717 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 ioc->name, diag0val));
3719 return -3;
3720 }
3721
3722 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3723 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3724 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3725 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3726 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3727 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3728
3729 /* Set the DiagRwEn and Disable ARM bits */
3730 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3731
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732 fwSize = (pFwHeader->ImageSize + 3)/4;
3733 ptrFw = (u32 *) pFwHeader;
3734
3735 /* Write the LoadStartAddress to the DiagRw Address Register
3736 * using Programmed IO
3737 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003738 if (ioc->errata_flag_1064)
3739 pci_enable_io_access(ioc->pcidev);
3740
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303742 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743 ioc->name, pFwHeader->LoadStartAddress));
3744
Prakash, Sathya436ace72007-07-24 15:42:08 +05303745 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 ioc->name, fwSize*4, ptrFw));
3747 while (fwSize--) {
3748 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3749 }
3750
3751 nextImage = pFwHeader->NextImageHeaderOffset;
3752 while (nextImage) {
3753 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3754
3755 load_addr = pExtImage->LoadStartAddress;
3756
3757 fwSize = (pExtImage->ImageSize + 3) >> 2;
3758 ptrFw = (u32 *)pExtImage;
3759
Prakash, Sathya436ace72007-07-24 15:42:08 +05303760 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 +02003761 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3763
3764 while (fwSize--) {
3765 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3766 }
3767 nextImage = pExtImage->NextImageHeaderOffset;
3768 }
3769
3770 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303771 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3773
3774 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303775 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3777
3778 /* Clear the internal flash bad bit - autoincrementing register,
3779 * so must do two writes.
3780 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003781 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003782 /*
3783 * 1030 and 1035 H/W errata, workaround to access
3784 * the ClearFlashBadSignatureBit
3785 */
3786 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3787 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3788 diagRwData |= 0x40000000;
3789 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3790 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3791
3792 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3793 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3794 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3795 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3796
3797 /* wait 1 msec */
3798 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003799 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003800 } else {
3801 mdelay (1);
3802 }
3803 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003805 if (ioc->errata_flag_1064)
3806 pci_disable_io_access(ioc->pcidev);
3807
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303809 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003810 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003812 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303813 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814 ioc->name, diag0val));
3815 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3816
3817 /* Write 0xFF to reset the sequencer */
3818 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3819
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003820 if (ioc->bus_type == SAS) {
3821 ioc_state = mpt_GetIocState(ioc, 0);
3822 if ( (GetIocFacts(ioc, sleepFlag,
3823 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303824 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003825 ioc->name, ioc_state));
3826 return -EFAULT;
3827 }
3828 }
3829
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830 for (count=0; count<HZ*20; count++) {
3831 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303832 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3833 "downloadboot successful! (count=%d) IocState=%x\n",
3834 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003835 if (ioc->bus_type == SAS) {
3836 return 0;
3837 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303839 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3840 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 ioc->name));
3842 return -EFAULT;
3843 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303844 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3845 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846 ioc->name));
3847 return 0;
3848 }
3849 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003850 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003851 } else {
3852 mdelay (10);
3853 }
3854 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303855 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3856 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 return -EFAULT;
3858}
3859
3860/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003861/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862 * KickStart - Perform hard reset of MPT adapter.
3863 * @ioc: Pointer to MPT_ADAPTER structure
3864 * @force: Force hard reset
3865 * @sleepFlag: Specifies whether the process can sleep
3866 *
3867 * This routine places MPT adapter in diagnostic mode via the
3868 * WriteSequence register, and then performs a hard reset of adapter
3869 * via the Diagnostic register.
3870 *
3871 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3872 * or NO_SLEEP (interrupt thread, use mdelay)
3873 * force - 1 if doorbell active, board fault state
3874 * board operational, IOC_RECOVERY or
3875 * IOC_BRINGUP and there is an alt_ioc.
3876 * 0 else
3877 *
3878 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003879 * 1 - hard reset, READY
3880 * 0 - no reset due to History bit, READY
3881 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882 * OR reset but failed to come READY
3883 * -2 - no reset, could not enter DIAG mode
3884 * -3 - reset but bad FW bit
3885 */
3886static int
3887KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3888{
3889 int hard_reset_done = 0;
3890 u32 ioc_state=0;
3891 int cnt,cntdn;
3892
Eric Moore29dd3602007-09-14 18:46:51 -06003893 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003894 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 /* Always issue a Msg Unit Reset first. This will clear some
3896 * SCSI bus hang conditions.
3897 */
3898 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3899
3900 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003901 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 } else {
3903 mdelay (1000);
3904 }
3905 }
3906
3907 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3908 if (hard_reset_done < 0)
3909 return hard_reset_done;
3910
Prakash, Sathya436ace72007-07-24 15:42:08 +05303911 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003912 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913
3914 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3915 for (cnt=0; cnt<cntdn; cnt++) {
3916 ioc_state = mpt_GetIocState(ioc, 1);
3917 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303918 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919 ioc->name, cnt));
3920 return hard_reset_done;
3921 }
3922 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003923 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 } else {
3925 mdelay (10);
3926 }
3927 }
3928
Eric Moore29dd3602007-09-14 18:46:51 -06003929 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3930 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931 return -1;
3932}
3933
3934/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003935/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936 * mpt_diag_reset - Perform hard reset of the adapter.
3937 * @ioc: Pointer to MPT_ADAPTER structure
3938 * @ignore: Set if to honor and clear to ignore
3939 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003940 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941 * else set to NO_SLEEP (use mdelay instead)
3942 *
3943 * This routine places the adapter in diagnostic mode via the
3944 * WriteSequence register and then performs a hard reset of adapter
3945 * via the Diagnostic register. Adapter should be in ready state
3946 * upon successful completion.
3947 *
3948 * Returns: 1 hard reset successful
3949 * 0 no reset performed because reset history bit set
3950 * -2 enabling diagnostic mode failed
3951 * -3 diagnostic reset failed
3952 */
3953static int
3954mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3955{
3956 u32 diag0val;
3957 u32 doorbell;
3958 int hard_reset_done = 0;
3959 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303961 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Kashyap, Desaid1306912009-08-05 12:53:51 +05303962 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963
Eric Moorecd2c6192007-01-29 09:47:47 -07003964 /* Clear any existing interrupts */
3965 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3966
Eric Moore87cf8982006-06-27 16:09:26 -06003967 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303968
3969 if (!ignore)
3970 return 0;
3971
Prakash, Sathya436ace72007-07-24 15:42:08 +05303972 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003973 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003974 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3975 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3976 if (sleepFlag == CAN_SLEEP)
3977 msleep(1);
3978 else
3979 mdelay(1);
3980
Kashyap, Desaid1306912009-08-05 12:53:51 +05303981 /*
3982 * Call each currently registered protocol IOC reset handler
3983 * with pre-reset indication.
3984 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3985 * MptResetHandlers[] registered yet.
3986 */
3987 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3988 if (MptResetHandlers[cb_idx])
3989 (*(MptResetHandlers[cb_idx]))(ioc,
3990 MPT_IOC_PRE_RESET);
3991 }
3992
Eric Moore87cf8982006-06-27 16:09:26 -06003993 for (count = 0; count < 60; count ++) {
3994 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3995 doorbell &= MPI_IOC_STATE_MASK;
3996
Prakash, Sathya436ace72007-07-24 15:42:08 +05303997 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003998 "looking for READY STATE: doorbell=%x"
3999 " count=%d\n",
4000 ioc->name, doorbell, count));
Kashyap, Desai2f187862009-05-29 16:52:37 +05304001
Eric Moore87cf8982006-06-27 16:09:26 -06004002 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004003 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06004004 }
4005
4006 /* wait 1 sec */
4007 if (sleepFlag == CAN_SLEEP)
4008 msleep(1000);
4009 else
4010 mdelay(1000);
4011 }
4012 return -1;
4013 }
4014
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 /* Use "Diagnostic reset" method! (only thing available!) */
4016 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4017
Prakash, Sathya436ace72007-07-24 15:42:08 +05304018 if (ioc->debug_level & MPT_DEBUG) {
4019 if (ioc->alt_ioc)
4020 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4021 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304023 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024
4025 /* Do the reset if we are told to ignore the reset history
4026 * or if the reset history is 0
4027 */
4028 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
4029 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4030 /* Write magic sequence to WriteSequence register
4031 * Loop until in diagnostic mode
4032 */
4033 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4034 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4035 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4036 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4037 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4038 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4039
4040 /* wait 100 msec */
4041 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004042 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 } else {
4044 mdelay (100);
4045 }
4046
4047 count++;
4048 if (count > 20) {
4049 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4050 ioc->name, diag0val);
4051 return -2;
4052
4053 }
4054
4055 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4056
Prakash, Sathya436ace72007-07-24 15:42:08 +05304057 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 ioc->name, diag0val));
4059 }
4060
Prakash, Sathya436ace72007-07-24 15:42:08 +05304061 if (ioc->debug_level & MPT_DEBUG) {
4062 if (ioc->alt_ioc)
4063 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4064 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304066 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067 /*
4068 * Disable the ARM (Bug fix)
4069 *
4070 */
4071 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004072 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073
4074 /*
4075 * Now hit the reset bit in the Diagnostic register
4076 * (THE BIG HAMMER!) (Clears DRWE bit).
4077 */
4078 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
4079 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304080 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081 ioc->name));
4082
4083 /*
4084 * Call each currently registered protocol IOC reset handler
4085 * with pre-reset indication.
4086 * NOTE: If we're doing _IOC_BRINGUP, there can be no
4087 * MptResetHandlers[] registered yet.
4088 */
Kashyap, Desaid1306912009-08-05 12:53:51 +05304089 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
4090 if (MptResetHandlers[cb_idx]) {
4091 mpt_signal_reset(cb_idx,
4092 ioc, MPT_IOC_PRE_RESET);
4093 if (ioc->alt_ioc) {
4094 mpt_signal_reset(cb_idx,
4095 ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096 }
4097 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098 }
4099
Eric Moore0ccdb002006-07-11 17:33:13 -06004100 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304101 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06004102 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304103 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4104 else
4105 cached_fw = NULL;
4106 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004107 /* If the DownloadBoot operation fails, the
4108 * IOC will be left unusable. This is a fatal error
4109 * case. _diag_reset will return < 0
4110 */
4111 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304112 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4114 break;
4115 }
4116
Prakash, Sathya436ace72007-07-24 15:42:08 +05304117 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304118 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004119 /* wait 1 sec */
4120 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004121 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122 } else {
4123 mdelay (1000);
4124 }
4125 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304126 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004127 printk(MYIOC_s_WARN_FMT
4128 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129 }
4130
4131 } else {
4132 /* Wait for FW to reload and for board
4133 * to go to the READY state.
4134 * Maximum wait is 60 seconds.
4135 * If fail, no error will check again
4136 * with calling program.
4137 */
4138 for (count = 0; count < 60; count ++) {
4139 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4140 doorbell &= MPI_IOC_STATE_MASK;
4141
Kashyap, Desai2f187862009-05-29 16:52:37 +05304142 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4143 "looking for READY STATE: doorbell=%x"
4144 " count=%d\n", ioc->name, doorbell, count));
4145
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146 if (doorbell == MPI_IOC_STATE_READY) {
4147 break;
4148 }
4149
4150 /* wait 1 sec */
4151 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004152 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153 } else {
4154 mdelay (1000);
4155 }
4156 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05304157
4158 if (doorbell != MPI_IOC_STATE_READY)
4159 printk(MYIOC_s_ERR_FMT "Failed to come READY "
4160 "after reset! IocState=%x", ioc->name,
4161 doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162 }
4163 }
4164
4165 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304166 if (ioc->debug_level & MPT_DEBUG) {
4167 if (ioc->alt_ioc)
4168 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4169 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4170 ioc->name, diag0val, diag1val));
4171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172
4173 /* Clear RESET_HISTORY bit! Place board in the
4174 * diagnostic mode to update the diag register.
4175 */
4176 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4177 count = 0;
4178 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4179 /* Write magic sequence to WriteSequence register
4180 * Loop until in diagnostic mode
4181 */
4182 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4183 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4184 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4185 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4186 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4187 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4188
4189 /* wait 100 msec */
4190 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004191 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 } else {
4193 mdelay (100);
4194 }
4195
4196 count++;
4197 if (count > 20) {
4198 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4199 ioc->name, diag0val);
4200 break;
4201 }
4202 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4203 }
4204 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4205 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4206 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4207 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4208 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4209 ioc->name);
4210 }
4211
4212 /* Disable Diagnostic Mode
4213 */
4214 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4215
4216 /* Check FW reload status flags.
4217 */
4218 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4219 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4220 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4221 ioc->name, diag0val);
4222 return -3;
4223 }
4224
Prakash, Sathya436ace72007-07-24 15:42:08 +05304225 if (ioc->debug_level & MPT_DEBUG) {
4226 if (ioc->alt_ioc)
4227 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4228 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304230 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231
4232 /*
4233 * Reset flag that says we've enabled event notification
4234 */
4235 ioc->facts.EventState = 0;
4236
4237 if (ioc->alt_ioc)
4238 ioc->alt_ioc->facts.EventState = 0;
4239
4240 return hard_reset_done;
4241}
4242
4243/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004244/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 * SendIocReset - Send IOCReset request to MPT adapter.
4246 * @ioc: Pointer to MPT_ADAPTER structure
4247 * @reset_type: reset type, expected values are
4248 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004249 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250 *
4251 * Send IOCReset request to the MPT adapter.
4252 *
4253 * Returns 0 for success, non-zero for failure.
4254 */
4255static int
4256SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4257{
4258 int r;
4259 u32 state;
4260 int cntdn, count;
4261
Prakash, Sathya436ace72007-07-24 15:42:08 +05304262 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 ioc->name, reset_type));
4264 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4265 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4266 return r;
4267
4268 /* FW ACK'd request, wait for READY state
4269 */
4270 count = 0;
4271 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4272
4273 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4274 cntdn--;
4275 count++;
4276 if (!cntdn) {
4277 if (sleepFlag != CAN_SLEEP)
4278 count *= 10;
4279
Kashyap, Desai2f187862009-05-29 16:52:37 +05304280 printk(MYIOC_s_ERR_FMT
4281 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
4282 ioc->name, state, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283 return -ETIME;
4284 }
4285
4286 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004287 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288 } else {
4289 mdelay (1); /* 1 msec delay */
4290 }
4291 }
4292
4293 /* TODO!
4294 * Cleanup all event stuff for this IOC; re-issue EventNotification
4295 * request if needed.
4296 */
4297 if (ioc->facts.Function)
4298 ioc->facts.EventState = 0;
4299
4300 return 0;
4301}
4302
4303/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004304/**
4305 * initChainBuffers - Allocate memory for and initialize chain buffers
4306 * @ioc: Pointer to MPT_ADAPTER structure
4307 *
4308 * Allocates memory for and initializes chain buffers,
4309 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310 */
4311static int
4312initChainBuffers(MPT_ADAPTER *ioc)
4313{
4314 u8 *mem;
4315 int sz, ii, num_chain;
4316 int scale, num_sge, numSGE;
4317
4318 /* ReqToChain size must equal the req_depth
4319 * index = req_idx
4320 */
4321 if (ioc->ReqToChain == NULL) {
4322 sz = ioc->req_depth * sizeof(int);
4323 mem = kmalloc(sz, GFP_ATOMIC);
4324 if (mem == NULL)
4325 return -1;
4326
4327 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304328 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329 ioc->name, mem, sz));
4330 mem = kmalloc(sz, GFP_ATOMIC);
4331 if (mem == NULL)
4332 return -1;
4333
4334 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304335 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 ioc->name, mem, sz));
4337 }
4338 for (ii = 0; ii < ioc->req_depth; ii++) {
4339 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4340 }
4341
4342 /* ChainToChain size must equal the total number
4343 * of chain buffers to be allocated.
4344 * index = chain_idx
4345 *
4346 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004347 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348 *
4349 * num_sge = num sge in request frame + last chain buffer
4350 * scale = num sge per chain buffer if no chain element
4351 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304352 scale = ioc->req_sz / ioc->SGE_size;
4353 if (ioc->sg_addr_size == sizeof(u64))
4354 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304356 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304358 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304360 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304362 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4363 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304365 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 ioc->name, num_sge, numSGE));
4367
Kashyap, Desai2f187862009-05-29 16:52:37 +05304368 if (ioc->bus_type == FC) {
4369 if (numSGE > MPT_SCSI_FC_SG_DEPTH)
4370 numSGE = MPT_SCSI_FC_SG_DEPTH;
4371 } else {
4372 if (numSGE > MPT_SCSI_SG_DEPTH)
4373 numSGE = MPT_SCSI_SG_DEPTH;
4374 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375
4376 num_chain = 1;
4377 while (numSGE - num_sge > 0) {
4378 num_chain++;
4379 num_sge += (scale - 1);
4380 }
4381 num_chain++;
4382
Prakash, Sathya436ace72007-07-24 15:42:08 +05304383 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384 ioc->name, numSGE, num_sge, num_chain));
4385
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004386 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 num_chain *= MPT_SCSI_CAN_QUEUE;
Anatolij Gustschinf1053a72009-12-12 14:52:21 +01004388 else if (ioc->bus_type == SAS)
4389 num_chain *= MPT_SAS_CAN_QUEUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390 else
4391 num_chain *= MPT_FC_CAN_QUEUE;
4392
4393 ioc->num_chain = num_chain;
4394
4395 sz = num_chain * sizeof(int);
4396 if (ioc->ChainToChain == NULL) {
4397 mem = kmalloc(sz, GFP_ATOMIC);
4398 if (mem == NULL)
4399 return -1;
4400
4401 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304402 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 ioc->name, mem, sz));
4404 } else {
4405 mem = (u8 *) ioc->ChainToChain;
4406 }
4407 memset(mem, 0xFF, sz);
4408 return num_chain;
4409}
4410
4411/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004412/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4414 * @ioc: Pointer to MPT_ADAPTER structure
4415 *
4416 * This routine allocates memory for the MPT reply and request frame
4417 * pools (if necessary), and primes the IOC reply FIFO with
4418 * reply frames.
4419 *
4420 * Returns 0 for success, non-zero for failure.
4421 */
4422static int
4423PrimeIocFifos(MPT_ADAPTER *ioc)
4424{
4425 MPT_FRAME_HDR *mf;
4426 unsigned long flags;
4427 dma_addr_t alloc_dma;
4428 u8 *mem;
4429 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304430 u64 dma_mask;
4431
4432 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433
4434 /* Prime reply FIFO... */
4435
4436 if (ioc->reply_frames == NULL) {
4437 if ( (num_chain = initChainBuffers(ioc)) < 0)
4438 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304439 /*
4440 * 1078 errata workaround for the 36GB limitation
4441 */
4442 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
Andrew Morton8e20ce92009-06-18 16:49:17 -07004443 ioc->dma_mask > DMA_BIT_MASK(35)) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304444 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4445 && !pci_set_consistent_dma_mask(ioc->pcidev,
4446 DMA_BIT_MASK(32))) {
Andrew Morton8e20ce92009-06-18 16:49:17 -07004447 dma_mask = DMA_BIT_MASK(35);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304448 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4449 "setting 35 bit addressing for "
4450 "Request/Reply/Chain and Sense Buffers\n",
4451 ioc->name));
4452 } else {
4453 /*Reseting DMA mask to 64 bit*/
4454 pci_set_dma_mask(ioc->pcidev,
4455 DMA_BIT_MASK(64));
4456 pci_set_consistent_dma_mask(ioc->pcidev,
4457 DMA_BIT_MASK(64));
4458
4459 printk(MYIOC_s_ERR_FMT
4460 "failed setting 35 bit addressing for "
4461 "Request/Reply/Chain and Sense Buffers\n",
4462 ioc->name);
4463 return -1;
4464 }
4465 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466
4467 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304468 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304470 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 ioc->name, reply_sz, reply_sz));
4472
4473 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304474 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304476 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 ioc->name, sz, sz));
4478 total_size += sz;
4479
4480 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304481 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304483 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 ioc->name, sz, sz, num_chain));
4485
4486 total_size += sz;
4487 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4488 if (mem == NULL) {
4489 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4490 ioc->name);
4491 goto out_fail;
4492 }
4493
Prakash, Sathya436ace72007-07-24 15:42:08 +05304494 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4496
4497 memset(mem, 0, total_size);
4498 ioc->alloc_total += total_size;
4499 ioc->alloc = mem;
4500 ioc->alloc_dma = alloc_dma;
4501 ioc->alloc_sz = total_size;
4502 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4503 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4504
Prakash, Sathya436ace72007-07-24 15:42:08 +05304505 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004506 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4507
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 alloc_dma += reply_sz;
4509 mem += reply_sz;
4510
4511 /* Request FIFO - WE manage this! */
4512
4513 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4514 ioc->req_frames_dma = alloc_dma;
4515
Prakash, Sathya436ace72007-07-24 15:42:08 +05304516 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 ioc->name, mem, (void *)(ulong)alloc_dma));
4518
4519 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4520
4521#if defined(CONFIG_MTRR) && 0
4522 /*
4523 * Enable Write Combining MTRR for IOC's memory region.
4524 * (at least as much as we can; "size and base must be
4525 * multiples of 4 kiB"
4526 */
4527 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4528 sz,
4529 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304530 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531 ioc->name, ioc->req_frames_dma, sz));
4532#endif
4533
4534 for (i = 0; i < ioc->req_depth; i++) {
4535 alloc_dma += ioc->req_sz;
4536 mem += ioc->req_sz;
4537 }
4538
4539 ioc->ChainBuffer = mem;
4540 ioc->ChainBufferDMA = alloc_dma;
4541
Prakash, Sathya436ace72007-07-24 15:42:08 +05304542 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4544
4545 /* Initialize the free chain Q.
4546 */
4547
4548 INIT_LIST_HEAD(&ioc->FreeChainQ);
4549
4550 /* Post the chain buffers to the FreeChainQ.
4551 */
4552 mem = (u8 *)ioc->ChainBuffer;
4553 for (i=0; i < num_chain; i++) {
4554 mf = (MPT_FRAME_HDR *) mem;
4555 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4556 mem += ioc->req_sz;
4557 }
4558
4559 /* Initialize Request frames linked list
4560 */
4561 alloc_dma = ioc->req_frames_dma;
4562 mem = (u8 *) ioc->req_frames;
4563
4564 spin_lock_irqsave(&ioc->FreeQlock, flags);
4565 INIT_LIST_HEAD(&ioc->FreeQ);
4566 for (i = 0; i < ioc->req_depth; i++) {
4567 mf = (MPT_FRAME_HDR *) mem;
4568
4569 /* Queue REQUESTs *internally*! */
4570 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4571
4572 mem += ioc->req_sz;
4573 }
4574 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4575
4576 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4577 ioc->sense_buf_pool =
4578 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4579 if (ioc->sense_buf_pool == NULL) {
4580 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4581 ioc->name);
4582 goto out_fail;
4583 }
4584
4585 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4586 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304587 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4589
4590 }
4591
4592 /* Post Reply frames to FIFO
4593 */
4594 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304595 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4597
4598 for (i = 0; i < ioc->reply_depth; i++) {
4599 /* Write each address to the IOC! */
4600 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4601 alloc_dma += ioc->reply_sz;
4602 }
4603
Andrew Morton8e20ce92009-06-18 16:49:17 -07004604 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304605 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4606 ioc->dma_mask))
4607 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4608 "restoring 64 bit addressing\n", ioc->name));
4609
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610 return 0;
4611
4612out_fail:
Kashyap, Desai2f187862009-05-29 16:52:37 +05304613
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 if (ioc->alloc != NULL) {
4615 sz = ioc->alloc_sz;
4616 pci_free_consistent(ioc->pcidev,
4617 sz,
4618 ioc->alloc, ioc->alloc_dma);
4619 ioc->reply_frames = NULL;
4620 ioc->req_frames = NULL;
4621 ioc->alloc_total -= sz;
4622 }
4623 if (ioc->sense_buf_pool != NULL) {
4624 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4625 pci_free_consistent(ioc->pcidev,
4626 sz,
4627 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4628 ioc->sense_buf_pool = NULL;
4629 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304630
Andrew Morton8e20ce92009-06-18 16:49:17 -07004631 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304632 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4633 DMA_BIT_MASK(64)))
4634 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4635 "restoring 64 bit addressing\n", ioc->name));
4636
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637 return -1;
4638}
4639
4640/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4641/**
4642 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4643 * from IOC via doorbell handshake method.
4644 * @ioc: Pointer to MPT_ADAPTER structure
4645 * @reqBytes: Size of the request in bytes
4646 * @req: Pointer to MPT request frame
4647 * @replyBytes: Expected size of the reply in bytes
4648 * @u16reply: Pointer to area where reply should be written
4649 * @maxwait: Max wait time for a reply (in seconds)
4650 * @sleepFlag: Specifies whether the process can sleep
4651 *
4652 * NOTES: It is the callers responsibility to byte-swap fields in the
4653 * request which are greater than 1 byte in size. It is also the
4654 * callers responsibility to byte-swap response fields which are
4655 * greater than 1 byte in size.
4656 *
4657 * Returns 0 for success, non-zero for failure.
4658 */
4659static int
4660mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004661 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662{
4663 MPIDefaultReply_t *mptReply;
4664 int failcnt = 0;
4665 int t;
4666
4667 /*
4668 * Get ready to cache a handshake reply
4669 */
4670 ioc->hs_reply_idx = 0;
4671 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4672 mptReply->MsgLength = 0;
4673
4674 /*
4675 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4676 * then tell IOC that we want to handshake a request of N words.
4677 * (WRITE u32val to Doorbell reg).
4678 */
4679 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4680 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4681 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4682 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4683
4684 /*
4685 * Wait for IOC's doorbell handshake int
4686 */
4687 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4688 failcnt++;
4689
Prakash, Sathya436ace72007-07-24 15:42:08 +05304690 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4692
4693 /* Read doorbell and check for active bit */
4694 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4695 return -1;
4696
4697 /*
4698 * Clear doorbell int (WRITE 0 to IntStatus reg),
4699 * then wait for IOC to ACKnowledge that it's ready for
4700 * our handshake request.
4701 */
4702 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4703 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4704 failcnt++;
4705
4706 if (!failcnt) {
4707 int ii;
4708 u8 *req_as_bytes = (u8 *) req;
4709
4710 /*
4711 * Stuff request words via doorbell handshake,
4712 * with ACK from IOC for each.
4713 */
4714 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4715 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4716 (req_as_bytes[(ii*4) + 1] << 8) |
4717 (req_as_bytes[(ii*4) + 2] << 16) |
4718 (req_as_bytes[(ii*4) + 3] << 24));
4719
4720 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4721 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4722 failcnt++;
4723 }
4724
Prakash, Sathya436ace72007-07-24 15:42:08 +05304725 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004726 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727
Prakash, Sathya436ace72007-07-24 15:42:08 +05304728 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4730
4731 /*
4732 * Wait for completion of doorbell handshake reply from the IOC
4733 */
4734 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4735 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004736
Prakash, Sathya436ace72007-07-24 15:42:08 +05304737 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4739
4740 /*
4741 * Copy out the cached reply...
4742 */
4743 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4744 u16reply[ii] = ioc->hs_reply[ii];
4745 } else {
4746 return -99;
4747 }
4748
4749 return -failcnt;
4750}
4751
4752/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004753/**
4754 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 * @ioc: Pointer to MPT_ADAPTER structure
4756 * @howlong: How long to wait (in seconds)
4757 * @sleepFlag: Specifies whether the process can sleep
4758 *
4759 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004760 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4761 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 *
4763 * Returns a negative value on failure, else wait loop count.
4764 */
4765static int
4766WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4767{
4768 int cntdn;
4769 int count = 0;
4770 u32 intstat=0;
4771
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004772 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773
4774 if (sleepFlag == CAN_SLEEP) {
4775 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004776 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4778 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4779 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780 count++;
4781 }
4782 } else {
4783 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004784 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4786 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4787 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 count++;
4789 }
4790 }
4791
4792 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304793 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794 ioc->name, count));
4795 return count;
4796 }
4797
4798 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4799 ioc->name, count, intstat);
4800 return -1;
4801}
4802
4803/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004804/**
4805 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 * @ioc: Pointer to MPT_ADAPTER structure
4807 * @howlong: How long to wait (in seconds)
4808 * @sleepFlag: Specifies whether the process can sleep
4809 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004810 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4811 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 *
4813 * Returns a negative value on failure, else wait loop count.
4814 */
4815static int
4816WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4817{
4818 int cntdn;
4819 int count = 0;
4820 u32 intstat=0;
4821
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004822 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 if (sleepFlag == CAN_SLEEP) {
4824 while (--cntdn) {
4825 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4826 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4827 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004828 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829 count++;
4830 }
4831 } else {
4832 while (--cntdn) {
4833 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4834 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4835 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004836 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 count++;
4838 }
4839 }
4840
4841 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304842 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843 ioc->name, count, howlong));
4844 return count;
4845 }
4846
4847 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4848 ioc->name, count, intstat);
4849 return -1;
4850}
4851
4852/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004853/**
4854 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855 * @ioc: Pointer to MPT_ADAPTER structure
4856 * @howlong: How long to wait (in seconds)
4857 * @sleepFlag: Specifies whether the process can sleep
4858 *
4859 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4860 * Reply is cached to IOC private area large enough to hold a maximum
4861 * of 128 bytes of reply data.
4862 *
4863 * Returns a negative value on failure, else size of reply in WORDS.
4864 */
4865static int
4866WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4867{
4868 int u16cnt = 0;
4869 int failcnt = 0;
4870 int t;
4871 u16 *hs_reply = ioc->hs_reply;
4872 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4873 u16 hword;
4874
4875 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4876
4877 /*
4878 * Get first two u16's so we can look at IOC's intended reply MsgLength
4879 */
4880 u16cnt=0;
4881 if ((t = WaitForDoorbellInt(ioc, howlong, 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 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4887 failcnt++;
4888 else {
4889 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4890 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4891 }
4892 }
4893
Prakash, Sathya436ace72007-07-24 15:42:08 +05304894 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004895 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4897
4898 /*
4899 * If no error (and IOC said MsgLength is > 0), piece together
4900 * reply 16 bits at a time.
4901 */
4902 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4903 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4904 failcnt++;
4905 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4906 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004907 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908 hs_reply[u16cnt] = hword;
4909 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4910 }
4911
4912 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4913 failcnt++;
4914 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4915
4916 if (failcnt) {
4917 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4918 ioc->name);
4919 return -failcnt;
4920 }
4921#if 0
4922 else if (u16cnt != (2 * mptReply->MsgLength)) {
4923 return -101;
4924 }
4925 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4926 return -102;
4927 }
4928#endif
4929
Prakash, Sathya436ace72007-07-24 15:42:08 +05304930 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004931 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932
Prakash, Sathya436ace72007-07-24 15:42:08 +05304933 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004934 ioc->name, t, u16cnt/2));
4935 return u16cnt/2;
4936}
4937
4938/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004939/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004940 * GetLanConfigPages - Fetch LANConfig pages.
4941 * @ioc: Pointer to MPT_ADAPTER structure
4942 *
4943 * Return: 0 for success
4944 * -ENOMEM if no memory available
4945 * -EPERM if not allowed due to ISR context
4946 * -EAGAIN if no msg frames currently available
4947 * -EFAULT for non-successful reply or no reply (timeout)
4948 */
4949static int
4950GetLanConfigPages(MPT_ADAPTER *ioc)
4951{
4952 ConfigPageHeader_t hdr;
4953 CONFIGPARMS cfg;
4954 LANPage0_t *ppage0_alloc;
4955 dma_addr_t page0_dma;
4956 LANPage1_t *ppage1_alloc;
4957 dma_addr_t page1_dma;
4958 int rc = 0;
4959 int data_sz;
4960 int copy_sz;
4961
4962 /* Get LAN Page 0 header */
4963 hdr.PageVersion = 0;
4964 hdr.PageLength = 0;
4965 hdr.PageNumber = 0;
4966 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004967 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004968 cfg.physAddr = -1;
4969 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4970 cfg.dir = 0;
4971 cfg.pageAddr = 0;
4972 cfg.timeout = 0;
4973
4974 if ((rc = mpt_config(ioc, &cfg)) != 0)
4975 return rc;
4976
4977 if (hdr.PageLength > 0) {
4978 data_sz = hdr.PageLength * 4;
4979 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4980 rc = -ENOMEM;
4981 if (ppage0_alloc) {
4982 memset((u8 *)ppage0_alloc, 0, data_sz);
4983 cfg.physAddr = page0_dma;
4984 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4985
4986 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4987 /* save the data */
4988 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4989 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4990
4991 }
4992
4993 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4994
4995 /* FIXME!
4996 * Normalize endianness of structure data,
4997 * by byte-swapping all > 1 byte fields!
4998 */
4999
5000 }
5001
5002 if (rc)
5003 return rc;
5004 }
5005
5006 /* Get LAN Page 1 header */
5007 hdr.PageVersion = 0;
5008 hdr.PageLength = 0;
5009 hdr.PageNumber = 1;
5010 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005011 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005012 cfg.physAddr = -1;
5013 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5014 cfg.dir = 0;
5015 cfg.pageAddr = 0;
5016
5017 if ((rc = mpt_config(ioc, &cfg)) != 0)
5018 return rc;
5019
5020 if (hdr.PageLength == 0)
5021 return 0;
5022
5023 data_sz = hdr.PageLength * 4;
5024 rc = -ENOMEM;
5025 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
5026 if (ppage1_alloc) {
5027 memset((u8 *)ppage1_alloc, 0, data_sz);
5028 cfg.physAddr = page1_dma;
5029 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5030
5031 if ((rc = mpt_config(ioc, &cfg)) == 0) {
5032 /* save the data */
5033 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
5034 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
5035 }
5036
5037 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
5038
5039 /* FIXME!
5040 * Normalize endianness of structure data,
5041 * by byte-swapping all > 1 byte fields!
5042 */
5043
5044 }
5045
5046 return rc;
5047}
5048
5049/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005050/**
5051 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005052 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005053 * @persist_opcode: see below
5054 *
5055 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
5056 * devices not currently present.
5057 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
5058 *
5059 * NOTE: Don't use not this function during interrupt time.
5060 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005061 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005062 */
5063
5064/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5065int
5066mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
5067{
5068 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
5069 SasIoUnitControlReply_t *sasIoUnitCntrReply;
5070 MPT_FRAME_HDR *mf = NULL;
5071 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305072 int ret = 0;
5073 unsigned long timeleft;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005074
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305075 mutex_lock(&ioc->mptbase_cmds.mutex);
5076
5077 /* init the internal cmd struct */
5078 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
5079 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005080
5081 /* insure garbage is not sent to fw */
5082 switch(persist_opcode) {
5083
5084 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
5085 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
5086 break;
5087
5088 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305089 ret = -1;
5090 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005091 }
5092
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305093 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
5094 __func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005095
5096 /* Get a MF for this command.
5097 */
5098 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305099 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
5100 ret = -1;
5101 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005102 }
5103
5104 mpi_hdr = (MPIHeader_t *) mf;
5105 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
5106 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
5107 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
5108 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
5109 sasIoUnitCntrReq->Operation = persist_opcode;
5110
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005111 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305112 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
5113 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
5114 ret = -ETIME;
5115 printk(KERN_DEBUG "%s: failed\n", __func__);
5116 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
5117 goto out;
5118 if (!timeleft) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09005119 printk(MYIOC_s_WARN_FMT
5120 "Issuing Reset from %s!!, doorbell=0x%08x\n",
5121 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05305122 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305123 mpt_free_msg_frame(ioc, mf);
5124 }
5125 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005126 }
5127
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305128 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
5129 ret = -1;
5130 goto out;
5131 }
5132
5133 sasIoUnitCntrReply =
5134 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5135 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5136 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5137 __func__, sasIoUnitCntrReply->IOCStatus,
5138 sasIoUnitCntrReply->IOCLogInfo);
5139 printk(KERN_DEBUG "%s: failed\n", __func__);
5140 ret = -1;
5141 } else
5142 printk(KERN_DEBUG "%s: success\n", __func__);
5143 out:
5144
5145 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5146 mutex_unlock(&ioc->mptbase_cmds.mutex);
5147 return ret;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005148}
5149
5150/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005151
5152static void
5153mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5154 MpiEventDataRaid_t * pRaidEventData)
5155{
5156 int volume;
5157 int reason;
5158 int disk;
5159 int status;
5160 int flags;
5161 int state;
5162
5163 volume = pRaidEventData->VolumeID;
5164 reason = pRaidEventData->ReasonCode;
5165 disk = pRaidEventData->PhysDiskNum;
5166 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5167 flags = (status >> 0) & 0xff;
5168 state = (status >> 8) & 0xff;
5169
5170 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5171 return;
5172 }
5173
5174 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5175 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5176 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005177 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5178 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005179 } else {
5180 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5181 ioc->name, volume);
5182 }
5183
5184 switch(reason) {
5185 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5186 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5187 ioc->name);
5188 break;
5189
5190 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5191
5192 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5193 ioc->name);
5194 break;
5195
5196 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5197 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5198 ioc->name);
5199 break;
5200
5201 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5202 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5203 ioc->name,
5204 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5205 ? "optimal"
5206 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5207 ? "degraded"
5208 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5209 ? "failed"
5210 : "state unknown",
5211 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5212 ? ", enabled" : "",
5213 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5214 ? ", quiesced" : "",
5215 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5216 ? ", resync in progress" : "" );
5217 break;
5218
5219 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5220 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5221 ioc->name, disk);
5222 break;
5223
5224 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5225 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5226 ioc->name);
5227 break;
5228
5229 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5230 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5231 ioc->name);
5232 break;
5233
5234 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5235 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5236 ioc->name);
5237 break;
5238
5239 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5240 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5241 ioc->name,
5242 state == MPI_PHYSDISK0_STATUS_ONLINE
5243 ? "online"
5244 : state == MPI_PHYSDISK0_STATUS_MISSING
5245 ? "missing"
5246 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5247 ? "not compatible"
5248 : state == MPI_PHYSDISK0_STATUS_FAILED
5249 ? "failed"
5250 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5251 ? "initializing"
5252 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5253 ? "offline requested"
5254 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5255 ? "failed requested"
5256 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5257 ? "offline"
5258 : "state unknown",
5259 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5260 ? ", out of sync" : "",
5261 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5262 ? ", quiesced" : "" );
5263 break;
5264
5265 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5266 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5267 ioc->name, disk);
5268 break;
5269
5270 case MPI_EVENT_RAID_RC_SMART_DATA:
5271 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5272 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5273 break;
5274
5275 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5276 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5277 ioc->name, disk);
5278 break;
5279 }
5280}
5281
5282/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005283/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005284 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5285 * @ioc: Pointer to MPT_ADAPTER structure
5286 *
5287 * Returns: 0 for success
5288 * -ENOMEM if no memory available
5289 * -EPERM if not allowed due to ISR context
5290 * -EAGAIN if no msg frames currently available
5291 * -EFAULT for non-successful reply or no reply (timeout)
5292 */
5293static int
5294GetIoUnitPage2(MPT_ADAPTER *ioc)
5295{
5296 ConfigPageHeader_t hdr;
5297 CONFIGPARMS cfg;
5298 IOUnitPage2_t *ppage_alloc;
5299 dma_addr_t page_dma;
5300 int data_sz;
5301 int rc;
5302
5303 /* Get the page header */
5304 hdr.PageVersion = 0;
5305 hdr.PageLength = 0;
5306 hdr.PageNumber = 2;
5307 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005308 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309 cfg.physAddr = -1;
5310 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5311 cfg.dir = 0;
5312 cfg.pageAddr = 0;
5313 cfg.timeout = 0;
5314
5315 if ((rc = mpt_config(ioc, &cfg)) != 0)
5316 return rc;
5317
5318 if (hdr.PageLength == 0)
5319 return 0;
5320
5321 /* Read the config page */
5322 data_sz = hdr.PageLength * 4;
5323 rc = -ENOMEM;
5324 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5325 if (ppage_alloc) {
5326 memset((u8 *)ppage_alloc, 0, data_sz);
5327 cfg.physAddr = page_dma;
5328 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5329
5330 /* If Good, save data */
5331 if ((rc = mpt_config(ioc, &cfg)) == 0)
5332 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5333
5334 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5335 }
5336
5337 return rc;
5338}
5339
5340/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005341/**
5342 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343 * @ioc: Pointer to a Adapter Strucutre
5344 * @portnum: IOC port number
5345 *
5346 * Return: -EFAULT if read of config page header fails
5347 * or if no nvram
5348 * If read of SCSI Port Page 0 fails,
5349 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5350 * Adapter settings: async, narrow
5351 * Return 1
5352 * If read of SCSI Port Page 2 fails,
5353 * Adapter settings valid
5354 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5355 * Return 1
5356 * Else
5357 * Both valid
5358 * Return 0
5359 * CHECK - what type of locking mechanisms should be used????
5360 */
5361static int
5362mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5363{
5364 u8 *pbuf;
5365 dma_addr_t buf_dma;
5366 CONFIGPARMS cfg;
5367 ConfigPageHeader_t header;
5368 int ii;
5369 int data, rc = 0;
5370
5371 /* Allocate memory
5372 */
5373 if (!ioc->spi_data.nvram) {
5374 int sz;
5375 u8 *mem;
5376 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5377 mem = kmalloc(sz, GFP_ATOMIC);
5378 if (mem == NULL)
5379 return -EFAULT;
5380
5381 ioc->spi_data.nvram = (int *) mem;
5382
Prakash, Sathya436ace72007-07-24 15:42:08 +05305383 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384 ioc->name, ioc->spi_data.nvram, sz));
5385 }
5386
5387 /* Invalidate NVRAM information
5388 */
5389 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5390 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5391 }
5392
5393 /* Read SPP0 header, allocate memory, then read page.
5394 */
5395 header.PageVersion = 0;
5396 header.PageLength = 0;
5397 header.PageNumber = 0;
5398 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005399 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400 cfg.physAddr = -1;
5401 cfg.pageAddr = portnum;
5402 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5403 cfg.dir = 0;
5404 cfg.timeout = 0; /* use default */
5405 if (mpt_config(ioc, &cfg) != 0)
5406 return -EFAULT;
5407
5408 if (header.PageLength > 0) {
5409 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5410 if (pbuf) {
5411 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5412 cfg.physAddr = buf_dma;
5413 if (mpt_config(ioc, &cfg) != 0) {
5414 ioc->spi_data.maxBusWidth = MPT_NARROW;
5415 ioc->spi_data.maxSyncOffset = 0;
5416 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5417 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5418 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305419 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5420 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005421 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422 } else {
5423 /* Save the Port Page 0 data
5424 */
5425 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5426 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5427 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5428
5429 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5430 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005431 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5432 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005433 ioc->name, pPP0->Capabilities));
5434 }
5435 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5436 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5437 if (data) {
5438 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5439 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5440 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305441 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5442 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005443 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005444 } else {
5445 ioc->spi_data.maxSyncOffset = 0;
5446 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5447 }
5448
5449 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5450
5451 /* Update the minSyncFactor based on bus type.
5452 */
5453 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5454 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5455
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005456 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305458 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5459 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005460 ioc->name, ioc->spi_data.minSyncFactor));
5461 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462 }
5463 }
5464 if (pbuf) {
5465 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5466 }
5467 }
5468 }
5469
5470 /* SCSI Port Page 2 - Read the header then the page.
5471 */
5472 header.PageVersion = 0;
5473 header.PageLength = 0;
5474 header.PageNumber = 2;
5475 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005476 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477 cfg.physAddr = -1;
5478 cfg.pageAddr = portnum;
5479 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5480 cfg.dir = 0;
5481 if (mpt_config(ioc, &cfg) != 0)
5482 return -EFAULT;
5483
5484 if (header.PageLength > 0) {
5485 /* Allocate memory and read SCSI Port Page 2
5486 */
5487 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5488 if (pbuf) {
5489 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5490 cfg.physAddr = buf_dma;
5491 if (mpt_config(ioc, &cfg) != 0) {
5492 /* Nvram data is left with INVALID mark
5493 */
5494 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005495 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5496
5497 /* This is an ATTO adapter, read Page2 accordingly
5498 */
5499 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5500 ATTODeviceInfo_t *pdevice = NULL;
5501 u16 ATTOFlags;
5502
5503 /* Save the Port Page 2 data
5504 * (reformat into a 32bit quantity)
5505 */
5506 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5507 pdevice = &pPP2->DeviceSettings[ii];
5508 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5509 data = 0;
5510
5511 /* Translate ATTO device flags to LSI format
5512 */
5513 if (ATTOFlags & ATTOFLAG_DISC)
5514 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5515 if (ATTOFlags & ATTOFLAG_ID_ENB)
5516 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5517 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5518 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5519 if (ATTOFlags & ATTOFLAG_TAGGED)
5520 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5521 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5522 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5523
5524 data = (data << 16) | (pdevice->Period << 8) | 10;
5525 ioc->spi_data.nvram[ii] = data;
5526 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527 } else {
5528 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5529 MpiDeviceInfo_t *pdevice = NULL;
5530
Moore, Ericd8e925d2006-01-16 18:53:06 -07005531 /*
5532 * Save "Set to Avoid SCSI Bus Resets" flag
5533 */
5534 ioc->spi_data.bus_reset =
5535 (le32_to_cpu(pPP2->PortFlags) &
5536 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5537 0 : 1 ;
5538
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539 /* Save the Port Page 2 data
5540 * (reformat into a 32bit quantity)
5541 */
5542 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5543 ioc->spi_data.PortFlags = data;
5544 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5545 pdevice = &pPP2->DeviceSettings[ii];
5546 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5547 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5548 ioc->spi_data.nvram[ii] = data;
5549 }
5550 }
5551
5552 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5553 }
5554 }
5555
5556 /* Update Adapter limits with those from NVRAM
5557 * Comment: Don't need to do this. Target performance
5558 * parameters will never exceed the adapters limits.
5559 */
5560
5561 return rc;
5562}
5563
5564/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005565/**
5566 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567 * @ioc: Pointer to a Adapter Strucutre
5568 * @portnum: IOC port number
5569 *
5570 * Return: -EFAULT if read of config page header fails
5571 * or 0 if success.
5572 */
5573static int
5574mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5575{
5576 CONFIGPARMS cfg;
5577 ConfigPageHeader_t header;
5578
5579 /* Read the SCSI Device Page 1 header
5580 */
5581 header.PageVersion = 0;
5582 header.PageLength = 0;
5583 header.PageNumber = 1;
5584 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005585 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005586 cfg.physAddr = -1;
5587 cfg.pageAddr = portnum;
5588 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5589 cfg.dir = 0;
5590 cfg.timeout = 0;
5591 if (mpt_config(ioc, &cfg) != 0)
5592 return -EFAULT;
5593
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005594 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5595 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596
5597 header.PageVersion = 0;
5598 header.PageLength = 0;
5599 header.PageNumber = 0;
5600 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5601 if (mpt_config(ioc, &cfg) != 0)
5602 return -EFAULT;
5603
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005604 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5605 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606
Prakash, Sathya436ace72007-07-24 15:42:08 +05305607 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005608 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5609
Prakash, Sathya436ace72007-07-24 15:42:08 +05305610 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5612 return 0;
5613}
5614
Eric Mooreb506ade2007-01-29 09:45:37 -07005615/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005616 * mpt_inactive_raid_list_free - This clears this link list.
5617 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005618 **/
5619static void
5620mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5621{
5622 struct inactive_raid_component_info *component_info, *pNext;
5623
5624 if (list_empty(&ioc->raid_data.inactive_list))
5625 return;
5626
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005627 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005628 list_for_each_entry_safe(component_info, pNext,
5629 &ioc->raid_data.inactive_list, list) {
5630 list_del(&component_info->list);
5631 kfree(component_info);
5632 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005633 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005634}
5635
5636/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005637 * 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 -07005638 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005639 * @ioc : pointer to per adapter structure
5640 * @channel : volume channel
5641 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005642 **/
5643static void
5644mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5645{
5646 CONFIGPARMS cfg;
5647 ConfigPageHeader_t hdr;
5648 dma_addr_t dma_handle;
5649 pRaidVolumePage0_t buffer = NULL;
5650 int i;
5651 RaidPhysDiskPage0_t phys_disk;
5652 struct inactive_raid_component_info *component_info;
5653 int handle_inactive_volumes;
5654
5655 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5656 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5657 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5658 cfg.pageAddr = (channel << 8) + id;
5659 cfg.cfghdr.hdr = &hdr;
5660 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5661
5662 if (mpt_config(ioc, &cfg) != 0)
5663 goto out;
5664
5665 if (!hdr.PageLength)
5666 goto out;
5667
5668 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5669 &dma_handle);
5670
5671 if (!buffer)
5672 goto out;
5673
5674 cfg.physAddr = dma_handle;
5675 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5676
5677 if (mpt_config(ioc, &cfg) != 0)
5678 goto out;
5679
5680 if (!buffer->NumPhysDisks)
5681 goto out;
5682
5683 handle_inactive_volumes =
5684 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5685 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5686 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5687 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5688
5689 if (!handle_inactive_volumes)
5690 goto out;
5691
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005692 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005693 for (i = 0; i < buffer->NumPhysDisks; i++) {
5694 if(mpt_raid_phys_disk_pg0(ioc,
5695 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5696 continue;
5697
5698 if ((component_info = kmalloc(sizeof (*component_info),
5699 GFP_KERNEL)) == NULL)
5700 continue;
5701
5702 component_info->volumeID = id;
5703 component_info->volumeBus = channel;
5704 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5705 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5706 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5707 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5708
5709 list_add_tail(&component_info->list,
5710 &ioc->raid_data.inactive_list);
5711 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005712 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005713
5714 out:
5715 if (buffer)
5716 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5717 dma_handle);
5718}
5719
5720/**
5721 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5722 * @ioc: Pointer to a Adapter Structure
5723 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5724 * @phys_disk: requested payload data returned
5725 *
5726 * Return:
5727 * 0 on success
5728 * -EFAULT if read of config page header fails or data pointer not NULL
5729 * -ENOMEM if pci_alloc failed
5730 **/
5731int
Kashyap, Desai2f187862009-05-29 16:52:37 +05305732mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
5733 RaidPhysDiskPage0_t *phys_disk)
Eric Mooreb506ade2007-01-29 09:45:37 -07005734{
Kashyap, Desai2f187862009-05-29 16:52:37 +05305735 CONFIGPARMS cfg;
5736 ConfigPageHeader_t hdr;
Eric Mooreb506ade2007-01-29 09:45:37 -07005737 dma_addr_t dma_handle;
5738 pRaidPhysDiskPage0_t buffer = NULL;
5739 int rc;
5740
5741 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5742 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
Kashyap, Desai2f187862009-05-29 16:52:37 +05305743 memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
Eric Mooreb506ade2007-01-29 09:45:37 -07005744
Kashyap, Desai2f187862009-05-29 16:52:37 +05305745 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
Eric Mooreb506ade2007-01-29 09:45:37 -07005746 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5747 cfg.cfghdr.hdr = &hdr;
5748 cfg.physAddr = -1;
5749 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5750
5751 if (mpt_config(ioc, &cfg) != 0) {
5752 rc = -EFAULT;
5753 goto out;
5754 }
5755
5756 if (!hdr.PageLength) {
5757 rc = -EFAULT;
5758 goto out;
5759 }
5760
5761 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5762 &dma_handle);
5763
5764 if (!buffer) {
5765 rc = -ENOMEM;
5766 goto out;
5767 }
5768
5769 cfg.physAddr = dma_handle;
5770 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5771 cfg.pageAddr = phys_disk_num;
5772
5773 if (mpt_config(ioc, &cfg) != 0) {
5774 rc = -EFAULT;
5775 goto out;
5776 }
5777
5778 rc = 0;
5779 memcpy(phys_disk, buffer, sizeof(*buffer));
5780 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5781
5782 out:
5783
5784 if (buffer)
5785 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5786 dma_handle);
5787
5788 return rc;
5789}
5790
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791/**
Kashyap, Desaia7938b02009-05-29 16:53:56 +05305792 * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
5793 * @ioc: Pointer to a Adapter Structure
5794 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5795 *
5796 * Return:
5797 * returns number paths
5798 **/
5799int
5800mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
5801{
5802 CONFIGPARMS cfg;
5803 ConfigPageHeader_t hdr;
5804 dma_addr_t dma_handle;
5805 pRaidPhysDiskPage1_t buffer = NULL;
5806 int rc;
5807
5808 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5809 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5810
5811 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5812 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5813 hdr.PageNumber = 1;
5814 cfg.cfghdr.hdr = &hdr;
5815 cfg.physAddr = -1;
5816 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5817
5818 if (mpt_config(ioc, &cfg) != 0) {
5819 rc = 0;
5820 goto out;
5821 }
5822
5823 if (!hdr.PageLength) {
5824 rc = 0;
5825 goto out;
5826 }
5827
5828 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5829 &dma_handle);
5830
5831 if (!buffer) {
5832 rc = 0;
5833 goto out;
5834 }
5835
5836 cfg.physAddr = dma_handle;
5837 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5838 cfg.pageAddr = phys_disk_num;
5839
5840 if (mpt_config(ioc, &cfg) != 0) {
5841 rc = 0;
5842 goto out;
5843 }
5844
5845 rc = buffer->NumPhysDiskPaths;
5846 out:
5847
5848 if (buffer)
5849 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5850 dma_handle);
5851
5852 return rc;
5853}
5854EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
5855
5856/**
5857 * mpt_raid_phys_disk_pg1 - returns phys disk page 1
5858 * @ioc: Pointer to a Adapter Structure
5859 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5860 * @phys_disk: requested payload data returned
5861 *
5862 * Return:
5863 * 0 on success
5864 * -EFAULT if read of config page header fails or data pointer not NULL
5865 * -ENOMEM if pci_alloc failed
5866 **/
5867int
5868mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
5869 RaidPhysDiskPage1_t *phys_disk)
5870{
5871 CONFIGPARMS cfg;
5872 ConfigPageHeader_t hdr;
5873 dma_addr_t dma_handle;
5874 pRaidPhysDiskPage1_t buffer = NULL;
5875 int rc;
5876 int i;
5877 __le64 sas_address;
5878
5879 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5880 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5881 rc = 0;
5882
5883 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5884 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5885 hdr.PageNumber = 1;
5886 cfg.cfghdr.hdr = &hdr;
5887 cfg.physAddr = -1;
5888 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5889
5890 if (mpt_config(ioc, &cfg) != 0) {
5891 rc = -EFAULT;
5892 goto out;
5893 }
5894
5895 if (!hdr.PageLength) {
5896 rc = -EFAULT;
5897 goto out;
5898 }
5899
5900 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5901 &dma_handle);
5902
5903 if (!buffer) {
5904 rc = -ENOMEM;
5905 goto out;
5906 }
5907
5908 cfg.physAddr = dma_handle;
5909 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5910 cfg.pageAddr = phys_disk_num;
5911
5912 if (mpt_config(ioc, &cfg) != 0) {
5913 rc = -EFAULT;
5914 goto out;
5915 }
5916
5917 phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
5918 phys_disk->PhysDiskNum = phys_disk_num;
5919 for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
5920 phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
5921 phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
5922 phys_disk->Path[i].OwnerIdentifier =
5923 buffer->Path[i].OwnerIdentifier;
5924 phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
5925 memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
5926 sas_address = le64_to_cpu(sas_address);
5927 memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
5928 memcpy(&sas_address,
5929 &buffer->Path[i].OwnerWWID, sizeof(__le64));
5930 sas_address = le64_to_cpu(sas_address);
5931 memcpy(&phys_disk->Path[i].OwnerWWID,
5932 &sas_address, sizeof(__le64));
5933 }
5934
5935 out:
5936
5937 if (buffer)
5938 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5939 dma_handle);
5940
5941 return rc;
5942}
5943EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
5944
5945
5946/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005947 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5948 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005949 *
5950 * Return:
5951 * 0 on success
5952 * -EFAULT if read of config page header fails or data pointer not NULL
5953 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005954 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955int
5956mpt_findImVolumes(MPT_ADAPTER *ioc)
5957{
5958 IOCPage2_t *pIoc2;
5959 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960 dma_addr_t ioc2_dma;
5961 CONFIGPARMS cfg;
5962 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963 int rc = 0;
5964 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005965 int i;
5966
5967 if (!ioc->ir_firmware)
5968 return 0;
5969
5970 /* Free the old page
5971 */
5972 kfree(ioc->raid_data.pIocPg2);
5973 ioc->raid_data.pIocPg2 = NULL;
5974 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005975
5976 /* Read IOCP2 header then the page.
5977 */
5978 header.PageVersion = 0;
5979 header.PageLength = 0;
5980 header.PageNumber = 2;
5981 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005982 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005983 cfg.physAddr = -1;
5984 cfg.pageAddr = 0;
5985 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5986 cfg.dir = 0;
5987 cfg.timeout = 0;
5988 if (mpt_config(ioc, &cfg) != 0)
5989 return -EFAULT;
5990
5991 if (header.PageLength == 0)
5992 return -EFAULT;
5993
5994 iocpage2sz = header.PageLength * 4;
5995 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5996 if (!pIoc2)
5997 return -ENOMEM;
5998
5999 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6000 cfg.physAddr = ioc2_dma;
6001 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07006002 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006003
Eric Mooreb506ade2007-01-29 09:45:37 -07006004 mem = kmalloc(iocpage2sz, GFP_KERNEL);
Julia Lawall1c1acab2010-08-11 12:11:24 +02006005 if (!mem) {
6006 rc = -ENOMEM;
Eric Mooreb506ade2007-01-29 09:45:37 -07006007 goto out;
Julia Lawall1c1acab2010-08-11 12:11:24 +02006008 }
Eric Mooreb506ade2007-01-29 09:45:37 -07006009
Linus Torvalds1da177e2005-04-16 15:20:36 -07006010 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07006011 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006012
Eric Mooreb506ade2007-01-29 09:45:37 -07006013 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006014
Eric Mooreb506ade2007-01-29 09:45:37 -07006015 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
6016 mpt_inactive_raid_volumes(ioc,
6017 pIoc2->RaidVolume[i].VolumeBus,
6018 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006019
Eric Mooreb506ade2007-01-29 09:45:37 -07006020 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006021 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
6022
6023 return rc;
6024}
6025
Moore, Ericc972c702006-03-14 09:14:06 -07006026static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07006027mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
6028{
6029 IOCPage3_t *pIoc3;
6030 u8 *mem;
6031 CONFIGPARMS cfg;
6032 ConfigPageHeader_t header;
6033 dma_addr_t ioc3_dma;
6034 int iocpage3sz = 0;
6035
6036 /* Free the old page
6037 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006038 kfree(ioc->raid_data.pIocPg3);
6039 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006040
6041 /* There is at least one physical disk.
6042 * Read and save IOC Page 3
6043 */
6044 header.PageVersion = 0;
6045 header.PageLength = 0;
6046 header.PageNumber = 3;
6047 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006048 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006049 cfg.physAddr = -1;
6050 cfg.pageAddr = 0;
6051 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6052 cfg.dir = 0;
6053 cfg.timeout = 0;
6054 if (mpt_config(ioc, &cfg) != 0)
6055 return 0;
6056
6057 if (header.PageLength == 0)
6058 return 0;
6059
6060 /* Read Header good, alloc memory
6061 */
6062 iocpage3sz = header.PageLength * 4;
6063 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
6064 if (!pIoc3)
6065 return 0;
6066
6067 /* Read the Page and save the data
6068 * into malloc'd memory.
6069 */
6070 cfg.physAddr = ioc3_dma;
6071 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6072 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07006073 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006074 if (mem) {
6075 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006076 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077 }
6078 }
6079
6080 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
6081
6082 return 0;
6083}
6084
6085static void
6086mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
6087{
6088 IOCPage4_t *pIoc4;
6089 CONFIGPARMS cfg;
6090 ConfigPageHeader_t header;
6091 dma_addr_t ioc4_dma;
6092 int iocpage4sz;
6093
6094 /* Read and save IOC Page 4
6095 */
6096 header.PageVersion = 0;
6097 header.PageLength = 0;
6098 header.PageNumber = 4;
6099 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006100 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006101 cfg.physAddr = -1;
6102 cfg.pageAddr = 0;
6103 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6104 cfg.dir = 0;
6105 cfg.timeout = 0;
6106 if (mpt_config(ioc, &cfg) != 0)
6107 return;
6108
6109 if (header.PageLength == 0)
6110 return;
6111
6112 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
6113 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
6114 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
6115 if (!pIoc4)
6116 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06006117 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006118 } else {
6119 ioc4_dma = ioc->spi_data.IocPg4_dma;
6120 iocpage4sz = ioc->spi_data.IocPg4Sz;
6121 }
6122
6123 /* Read the Page into dma memory.
6124 */
6125 cfg.physAddr = ioc4_dma;
6126 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6127 if (mpt_config(ioc, &cfg) == 0) {
6128 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
6129 ioc->spi_data.IocPg4_dma = ioc4_dma;
6130 ioc->spi_data.IocPg4Sz = iocpage4sz;
6131 } else {
6132 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
6133 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06006134 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135 }
6136}
6137
6138static void
6139mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
6140{
6141 IOCPage1_t *pIoc1;
6142 CONFIGPARMS cfg;
6143 ConfigPageHeader_t header;
6144 dma_addr_t ioc1_dma;
6145 int iocpage1sz = 0;
6146 u32 tmp;
6147
6148 /* Check the Coalescing Timeout in IOC Page 1
6149 */
6150 header.PageVersion = 0;
6151 header.PageLength = 0;
6152 header.PageNumber = 1;
6153 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006154 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006155 cfg.physAddr = -1;
6156 cfg.pageAddr = 0;
6157 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6158 cfg.dir = 0;
6159 cfg.timeout = 0;
6160 if (mpt_config(ioc, &cfg) != 0)
6161 return;
6162
6163 if (header.PageLength == 0)
6164 return;
6165
6166 /* Read Header good, alloc memory
6167 */
6168 iocpage1sz = header.PageLength * 4;
6169 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
6170 if (!pIoc1)
6171 return;
6172
6173 /* Read the Page and check coalescing timeout
6174 */
6175 cfg.physAddr = ioc1_dma;
6176 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6177 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306178
Linus Torvalds1da177e2005-04-16 15:20:36 -07006179 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
6180 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
6181 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
6182
Prakash, Sathya436ace72007-07-24 15:42:08 +05306183 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006184 ioc->name, tmp));
6185
6186 if (tmp > MPT_COALESCING_TIMEOUT) {
6187 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
6188
6189 /* Write NVRAM and current
6190 */
6191 cfg.dir = 1;
6192 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
6193 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306194 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006195 ioc->name, MPT_COALESCING_TIMEOUT));
6196
6197 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
6198 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306199 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6200 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006201 ioc->name, MPT_COALESCING_TIMEOUT));
6202 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306203 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6204 "Reset NVRAM Coalescing Timeout Failed\n",
6205 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006206 }
6207
6208 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306209 dprintk(ioc, printk(MYIOC_s_WARN_FMT
6210 "Reset of Current Coalescing Timeout Failed!\n",
6211 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006212 }
6213 }
6214
6215 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306216 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217 }
6218 }
6219
6220 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
6221
6222 return;
6223}
6224
Prakash, Sathyaedb90682007-07-17 14:39:14 +05306225static void
6226mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
6227{
6228 CONFIGPARMS cfg;
6229 ConfigPageHeader_t hdr;
6230 dma_addr_t buf_dma;
6231 ManufacturingPage0_t *pbuf = NULL;
6232
6233 memset(&cfg, 0 , sizeof(CONFIGPARMS));
6234 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
6235
6236 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
6237 cfg.cfghdr.hdr = &hdr;
6238 cfg.physAddr = -1;
6239 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6240 cfg.timeout = 10;
6241
6242 if (mpt_config(ioc, &cfg) != 0)
6243 goto out;
6244
6245 if (!cfg.cfghdr.hdr->PageLength)
6246 goto out;
6247
6248 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6249 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
6250 if (!pbuf)
6251 goto out;
6252
6253 cfg.physAddr = buf_dma;
6254
6255 if (mpt_config(ioc, &cfg) != 0)
6256 goto out;
6257
6258 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
6259 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
6260 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
6261
6262 out:
6263
6264 if (pbuf)
6265 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
6266}
6267
Linus Torvalds1da177e2005-04-16 15:20:36 -07006268/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006269/**
6270 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006271 * @ioc: Pointer to MPT_ADAPTER structure
6272 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05306273 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274 */
6275static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05306276SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006277{
Kashyap, Desaifd761752009-05-29 16:39:06 +05306278 EventNotification_t evn;
6279 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006280
Kashyap, Desaifd761752009-05-29 16:39:06 +05306281 memset(&evn, 0, sizeof(EventNotification_t));
6282 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006283
Kashyap, Desaifd761752009-05-29 16:39:06 +05306284 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
6285 evn.Switch = EvSwitch;
6286 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006287
Kashyap, Desaifd761752009-05-29 16:39:06 +05306288 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6289 "Sending EventNotification (%d) request %p\n",
6290 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006291
Kashyap, Desaifd761752009-05-29 16:39:06 +05306292 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6293 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6294 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006295}
6296
6297/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6298/**
6299 * SendEventAck - Send EventAck request to MPT adapter.
6300 * @ioc: Pointer to MPT_ADAPTER structure
6301 * @evnp: Pointer to original EventNotification request
6302 */
6303static int
6304SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6305{
6306 EventAck_t *pAck;
6307
6308 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306309 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306310 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006311 return -1;
6312 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006313
Prakash, Sathya436ace72007-07-24 15:42:08 +05306314 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006315
6316 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6317 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006318 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006319 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006320 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006321 pAck->Event = evnp->Event;
6322 pAck->EventContext = evnp->EventContext;
6323
6324 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6325
6326 return 0;
6327}
6328
6329/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6330/**
6331 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006332 * @ioc: Pointer to an adapter structure
6333 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006334 * action, page address, direction, physical address
6335 * and pointer to a configuration page header
6336 * Page header is updated.
6337 *
6338 * Returns 0 for success
6339 * -EPERM if not allowed due to ISR context
6340 * -EAGAIN if no msg frames currently available
6341 * -EFAULT for non-successful reply or no reply (timeout)
6342 */
6343int
6344mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6345{
6346 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306347 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006348 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006349 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306350 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006351 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306352 long timeout;
6353 int ret;
6354 u8 page_type = 0, extend_page;
6355 unsigned long timeleft;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306356 unsigned long flags;
6357 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306358 u8 issue_hard_reset = 0;
6359 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006360
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006361 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006362 * to be in ISR context, because that is fatal!
6363 */
6364 in_isr = in_interrupt();
6365 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306366 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006367 ioc->name));
6368 return -EPERM;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306369 }
6370
6371 /* don't send a config page during diag reset */
6372 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6373 if (ioc->ioc_reset_in_progress) {
6374 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6375 "%s: busy with host reset\n", ioc->name, __func__));
6376 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6377 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006378 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306379 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006380
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306381 /* don't send if no chance of success */
6382 if (!ioc->active ||
6383 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6384 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6385 "%s: ioc not operational, %d, %xh\n",
6386 ioc->name, __func__, ioc->active,
6387 mpt_GetIocState(ioc, 0)));
6388 return -EFAULT;
6389 }
6390
6391 retry_config:
6392 mutex_lock(&ioc->mptbase_cmds.mutex);
6393 /* init the internal cmd struct */
6394 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6395 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6396
Linus Torvalds1da177e2005-04-16 15:20:36 -07006397 /* Get and Populate a free Frame
6398 */
6399 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306400 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6401 "mpt_config: no msg frames!\n", ioc->name));
6402 ret = -EAGAIN;
6403 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006404 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306405
Linus Torvalds1da177e2005-04-16 15:20:36 -07006406 pReq = (Config_t *)mf;
6407 pReq->Action = pCfg->action;
6408 pReq->Reserved = 0;
6409 pReq->ChainOffset = 0;
6410 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006411
6412 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006413 pReq->ExtPageLength = 0;
6414 pReq->ExtPageType = 0;
6415 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006416
Linus Torvalds1da177e2005-04-16 15:20:36 -07006417 for (ii=0; ii < 8; ii++)
6418 pReq->Reserved2[ii] = 0;
6419
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006420 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6421 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6422 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6423 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6424
6425 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6426 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6427 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6428 pReq->ExtPageType = pExtHdr->ExtPageType;
6429 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6430
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306431 /* Page Length must be treated as a reserved field for the
6432 * extended header.
6433 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006434 pReq->Header.PageLength = 0;
6435 }
6436
Linus Torvalds1da177e2005-04-16 15:20:36 -07006437 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6438
6439 /* Add a SGE to the config request.
6440 */
6441 if (pCfg->dir)
6442 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6443 else
6444 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6445
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306446 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6447 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006448 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306449 page_type = pReq->ExtPageType;
6450 extend_page = 1;
6451 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006452 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306453 page_type = pReq->Header.PageType;
6454 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006456
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306457 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6458 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6459 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6460
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306461 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306462 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006463 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306464 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6465 timeout);
6466 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6467 ret = -ETIME;
6468 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6469 "Failed Sending Config request type 0x%x, page 0x%x,"
6470 " action %d, status %xh, time left %ld\n\n",
6471 ioc->name, page_type, pReq->Header.PageNumber,
6472 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6473 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6474 goto out;
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05306475 if (!timeleft) {
6476 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6477 if (ioc->ioc_reset_in_progress) {
6478 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
6479 flags);
6480 printk(MYIOC_s_INFO_FMT "%s: host reset in"
6481 " progress mpt_config timed out.!!\n",
6482 __func__, ioc->name);
Dan Carpenter83ff74e2011-08-27 12:59:30 +03006483 mutex_unlock(&ioc->mptbase_cmds.mutex);
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05306484 return -EFAULT;
6485 }
6486 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306487 issue_hard_reset = 1;
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05306488 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306489 goto out;
6490 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006491
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306492 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6493 ret = -1;
6494 goto out;
6495 }
6496 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6497 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6498 if (ret == MPI_IOCSTATUS_SUCCESS) {
6499 if (extend_page) {
6500 pCfg->cfghdr.ehdr->ExtPageLength =
6501 le16_to_cpu(pReply->ExtPageLength);
6502 pCfg->cfghdr.ehdr->ExtPageType =
6503 pReply->ExtPageType;
6504 }
6505 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6506 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6507 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6508 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006509
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306510 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006511
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306512 if (retry_count)
6513 printk(MYIOC_s_INFO_FMT "Retry completed "
6514 "ret=0x%x timeleft=%ld\n",
6515 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006516
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306517 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6518 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006519
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306520out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006521
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306522 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6523 mutex_unlock(&ioc->mptbase_cmds.mutex);
6524 if (issue_hard_reset) {
6525 issue_hard_reset = 0;
Kei Tokunaga97009a22010-06-22 19:01:51 +09006526 printk(MYIOC_s_WARN_FMT
6527 "Issuing Reset from %s!!, doorbell=0x%08x\n",
6528 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaib3b97312010-03-18 19:14:51 +05306529 if (retry_count == 0) {
6530 if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0)
6531 retry_count++;
6532 } else
6533 mpt_HardResetHandler(ioc, CAN_SLEEP);
6534
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306535 mpt_free_msg_frame(ioc, mf);
6536 /* attempt one retry for a timed out command */
Kashyap, Desaib3b97312010-03-18 19:14:51 +05306537 if (retry_count < 2) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306538 printk(MYIOC_s_INFO_FMT
6539 "Attempting Retry Config request"
6540 " type 0x%x, page 0x%x,"
6541 " action %d\n", ioc->name, page_type,
6542 pCfg->cfghdr.hdr->PageNumber, pCfg->action);
6543 retry_count++;
6544 goto retry_config;
6545 }
6546 }
6547 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006548
Linus Torvalds1da177e2005-04-16 15:20:36 -07006549}
6550
6551/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006552/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006553 * mpt_ioc_reset - Base cleanup for hard reset
6554 * @ioc: Pointer to the adapter structure
6555 * @reset_phase: Indicates pre- or post-reset functionality
6556 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006557 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006558 */
6559static int
6560mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6561{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306562 switch (reset_phase) {
6563 case MPT_IOC_SETUP_RESET:
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306564 ioc->taskmgmt_quiesce_io = 1;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306565 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6566 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
6567 break;
6568 case MPT_IOC_PRE_RESET:
6569 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6570 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
6571 break;
6572 case MPT_IOC_POST_RESET:
6573 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6574 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
6575/* wake up mptbase_cmds */
6576 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6577 ioc->mptbase_cmds.status |=
6578 MPT_MGMT_STATUS_DID_IOCRESET;
6579 complete(&ioc->mptbase_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006580 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306581/* wake up taskmgmt_cmds */
6582 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
6583 ioc->taskmgmt_cmds.status |=
6584 MPT_MGMT_STATUS_DID_IOCRESET;
6585 complete(&ioc->taskmgmt_cmds.done);
6586 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306587 break;
6588 default:
6589 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006590 }
6591
6592 return 1; /* currently means nothing really */
6593}
6594
6595
6596#ifdef CONFIG_PROC_FS /* { */
6597/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6598/*
6599 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6600 */
6601/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006602/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006603 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6604 *
6605 * Returns 0 for success, non-zero for failure.
6606 */
6607static int
6608procmpt_create(void)
6609{
Linus Torvalds1da177e2005-04-16 15:20:36 -07006610 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6611 if (mpt_proc_root_dir == NULL)
6612 return -ENOTDIR;
6613
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006614 proc_create("summary", S_IRUGO, mpt_proc_root_dir, &mpt_summary_proc_fops);
6615 proc_create("version", S_IRUGO, mpt_proc_root_dir, &mpt_version_proc_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006616 return 0;
6617}
6618
6619/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006620/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006621 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6622 *
6623 * Returns 0 for success, non-zero for failure.
6624 */
6625static void
6626procmpt_destroy(void)
6627{
6628 remove_proc_entry("version", mpt_proc_root_dir);
6629 remove_proc_entry("summary", mpt_proc_root_dir);
6630 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6631}
6632
6633/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlap1f5cfe22010-08-14 13:05:50 -07006634/*
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006635 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006636 */
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006637static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan);
6638
6639static int mpt_summary_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006640{
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006641 MPT_ADAPTER *ioc = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006642
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006643 if (ioc) {
6644 seq_mpt_print_ioc_summary(ioc, m, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006645 } else {
6646 list_for_each_entry(ioc, &ioc_list, list) {
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006647 seq_mpt_print_ioc_summary(ioc, m, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006648 }
6649 }
6650
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006651 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006652}
6653
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006654static int mpt_summary_proc_open(struct inode *inode, struct file *file)
6655{
Al Virod9dda782013-03-31 18:16:14 -04006656 return single_open(file, mpt_summary_proc_show, PDE_DATA(inode));
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006657}
6658
6659static const struct file_operations mpt_summary_proc_fops = {
6660 .owner = THIS_MODULE,
6661 .open = mpt_summary_proc_open,
6662 .read = seq_read,
6663 .llseek = seq_lseek,
6664 .release = single_release,
6665};
6666
6667static int mpt_version_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006668{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306669 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006670 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006671 char *drvname;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006672
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006673 seq_printf(m, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6674 seq_printf(m, " Fusion MPT base driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006675
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006676 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006677 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006678 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306679 if (MptCallbacks[cb_idx]) {
6680 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006681 case MPTSPI_DRIVER:
6682 if (!scsi++) drvname = "SPI host";
6683 break;
6684 case MPTFC_DRIVER:
6685 if (!fc++) drvname = "FC host";
6686 break;
6687 case MPTSAS_DRIVER:
6688 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006689 break;
6690 case MPTLAN_DRIVER:
6691 if (!lan++) drvname = "LAN";
6692 break;
6693 case MPTSTM_DRIVER:
6694 if (!targ++) drvname = "SCSI target";
6695 break;
6696 case MPTCTL_DRIVER:
6697 if (!ctl++) drvname = "ioctl";
6698 break;
6699 }
6700
6701 if (drvname)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006702 seq_printf(m, " Fusion MPT %s driver\n", drvname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006703 }
6704 }
6705
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006706 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006707}
6708
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006709static int mpt_version_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006710{
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006711 return single_open(file, mpt_version_proc_show, NULL);
6712}
6713
6714static const struct file_operations mpt_version_proc_fops = {
6715 .owner = THIS_MODULE,
6716 .open = mpt_version_proc_open,
6717 .read = seq_read,
6718 .llseek = seq_lseek,
6719 .release = single_release,
6720};
6721
6722static int mpt_iocinfo_proc_show(struct seq_file *m, void *v)
6723{
6724 MPT_ADAPTER *ioc = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006725 char expVer[32];
6726 int sz;
6727 int p;
6728
6729 mpt_get_fw_exp_ver(expVer, ioc);
6730
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006731 seq_printf(m, "%s:", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006732 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006733 seq_printf(m, " (f/w download boot flag set)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006734// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006735// seq_printf(m, " CONFIG_CHECKSUM_FAIL!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006736
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006737 seq_printf(m, "\n ProductID = 0x%04x (%s)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006738 ioc->facts.ProductID,
6739 ioc->prod_name);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006740 seq_printf(m, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006741 if (ioc->facts.FWImageSize)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006742 seq_printf(m, " (fw_size=%d)", ioc->facts.FWImageSize);
6743 seq_printf(m, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6744 seq_printf(m, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6745 seq_printf(m, " EventState = 0x%02x\n", ioc->facts.EventState);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006746
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006747 seq_printf(m, " CurrentHostMfaHighAddr = 0x%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006748 ioc->facts.CurrentHostMfaHighAddr);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006749 seq_printf(m, " CurrentSenseBufferHighAddr = 0x%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006750 ioc->facts.CurrentSenseBufferHighAddr);
6751
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006752 seq_printf(m, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6753 seq_printf(m, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006754
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006755 seq_printf(m, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006756 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6757 /*
6758 * Rounding UP to nearest 4-kB boundary here...
6759 */
6760 sz = (ioc->req_sz * ioc->req_depth) + 128;
6761 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006762 seq_printf(m, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006763 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006764 seq_printf(m, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006765 4*ioc->facts.RequestFrameSize,
6766 ioc->facts.GlobalCredits);
6767
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006768 seq_printf(m, " Frames @ 0x%p (Dma @ 0x%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006769 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6770 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006771 seq_printf(m, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006772 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006773 seq_printf(m, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006774 ioc->facts.CurReplyFrameSize,
6775 ioc->facts.ReplyQueueDepth);
6776
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006777 seq_printf(m, " MaxDevices = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006778 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006779 seq_printf(m, " MaxBuses = %d\n", ioc->facts.MaxBuses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006780
6781 /* per-port info */
6782 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006783 seq_printf(m, " PortNumber = %d (of %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006784 p+1,
6785 ioc->facts.NumberOfPorts);
6786 if (ioc->bus_type == FC) {
6787 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6788 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006789 seq_printf(m, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006790 a[5], a[4], a[3], a[2], a[1], a[0]);
6791 }
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006792 seq_printf(m, " WWN = %08X%08X:%08X%08X\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006793 ioc->fc_port_page0[p].WWNN.High,
6794 ioc->fc_port_page0[p].WWNN.Low,
6795 ioc->fc_port_page0[p].WWPN.High,
6796 ioc->fc_port_page0[p].WWPN.Low);
6797 }
6798 }
6799
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006800 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006801}
6802
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006803static int mpt_iocinfo_proc_open(struct inode *inode, struct file *file)
6804{
Al Virod9dda782013-03-31 18:16:14 -04006805 return single_open(file, mpt_iocinfo_proc_show, PDE_DATA(inode));
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006806}
6807
6808static const struct file_operations mpt_iocinfo_proc_fops = {
6809 .owner = THIS_MODULE,
6810 .open = mpt_iocinfo_proc_open,
6811 .read = seq_read,
6812 .llseek = seq_lseek,
6813 .release = single_release,
6814};
Linus Torvalds1da177e2005-04-16 15:20:36 -07006815#endif /* CONFIG_PROC_FS } */
6816
6817/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6818static void
6819mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6820{
6821 buf[0] ='\0';
6822 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6823 sprintf(buf, " (Exp %02d%02d)",
6824 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6825 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6826
6827 /* insider hack! */
6828 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6829 strcat(buf, " [MDBG]");
6830 }
6831}
6832
6833/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6834/**
6835 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6836 * @ioc: Pointer to MPT_ADAPTER structure
6837 * @buffer: Pointer to buffer where IOC summary info should be written
6838 * @size: Pointer to number of bytes we wrote (set by this routine)
6839 * @len: Offset at which to start writing in buffer
6840 * @showlan: Display LAN stuff?
6841 *
6842 * This routine writes (english readable) ASCII text, which represents
6843 * a summary of IOC information, to a buffer.
6844 */
6845void
6846mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6847{
6848 char expVer[32];
6849 int y;
6850
6851 mpt_get_fw_exp_ver(expVer, ioc);
6852
6853 /*
6854 * Shorter summary of attached ioc's...
6855 */
6856 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6857 ioc->name,
6858 ioc->prod_name,
6859 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6860 ioc->facts.FWVersion.Word,
6861 expVer,
6862 ioc->facts.NumberOfPorts,
6863 ioc->req_depth);
6864
6865 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6866 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6867 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6868 a[5], a[4], a[3], a[2], a[1], a[0]);
6869 }
6870
Linus Torvalds1da177e2005-04-16 15:20:36 -07006871 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006872
6873 if (!ioc->active)
6874 y += sprintf(buffer+len+y, " (disabled)");
6875
6876 y += sprintf(buffer+len+y, "\n");
6877
6878 *size = y;
6879}
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006880
6881static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan)
6882{
6883 char expVer[32];
6884
6885 mpt_get_fw_exp_ver(expVer, ioc);
6886
6887 /*
6888 * Shorter summary of attached ioc's...
6889 */
6890 seq_printf(m, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6891 ioc->name,
6892 ioc->prod_name,
6893 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6894 ioc->facts.FWVersion.Word,
6895 expVer,
6896 ioc->facts.NumberOfPorts,
6897 ioc->req_depth);
6898
6899 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6900 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6901 seq_printf(m, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6902 a[5], a[4], a[3], a[2], a[1], a[0]);
6903 }
6904
6905 seq_printf(m, ", IRQ=%d", ioc->pci_irq);
6906
6907 if (!ioc->active)
6908 seq_printf(m, " (disabled)");
6909
6910 seq_putc(m, '\n');
6911}
6912
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306913/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006914 * mpt_set_taskmgmt_in_progress_flag - set flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306915 * @ioc: Pointer to MPT_ADAPTER structure
6916 *
6917 * Returns 0 for SUCCESS or -1 if FAILED.
6918 *
6919 * If -1 is return, then it was not possible to set the flags
6920 **/
6921int
6922mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6923{
6924 unsigned long flags;
6925 int retval;
6926
6927 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6928 if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
6929 (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
6930 retval = -1;
6931 goto out;
6932 }
6933 retval = 0;
6934 ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306935 ioc->taskmgmt_quiesce_io = 1;
6936 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306937 ioc->alt_ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306938 ioc->alt_ioc->taskmgmt_quiesce_io = 1;
6939 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306940 out:
6941 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6942 return retval;
6943}
6944EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
6945
6946/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006947 * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306948 * @ioc: Pointer to MPT_ADAPTER structure
6949 *
6950 **/
6951void
6952mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6953{
6954 unsigned long flags;
6955
6956 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6957 ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306958 ioc->taskmgmt_quiesce_io = 0;
6959 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306960 ioc->alt_ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306961 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
6962 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306963 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6964}
6965EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006966
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306967
6968/**
6969 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6970 * the kernel
6971 * @ioc: Pointer to MPT_ADAPTER structure
6972 *
6973 **/
6974void
6975mpt_halt_firmware(MPT_ADAPTER *ioc)
6976{
6977 u32 ioc_raw_state;
6978
6979 ioc_raw_state = mpt_GetIocState(ioc, 0);
6980
6981 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6982 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6983 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6984 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6985 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6986 } else {
6987 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6988 panic("%s: Firmware is halted due to command timeout\n",
6989 ioc->name);
6990 }
6991}
6992EXPORT_SYMBOL(mpt_halt_firmware);
6993
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306994/**
6995 * mpt_SoftResetHandler - Issues a less expensive reset
6996 * @ioc: Pointer to MPT_ADAPTER structure
6997 * @sleepFlag: Indicates if sleep or schedule must be called.
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306998 *
6999 * Returns 0 for SUCCESS or -1 if FAILED.
7000 *
7001 * Message Unit Reset - instructs the IOC to reset the Reply Post and
7002 * Free FIFO's. All the Message Frames on Reply Free FIFO are discarded.
7003 * All posted buffers are freed, and event notification is turned off.
Lucas De Marchi25985ed2011-03-30 22:57:33 -03007004 * IOC doesn't reply to any outstanding request. This will transfer IOC
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05307005 * to READY state.
7006 **/
Joe Lawrence5767d252014-06-25 17:05:49 -04007007static int
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05307008mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
7009{
7010 int rc;
7011 int ii;
7012 u8 cb_idx;
7013 unsigned long flags;
7014 u32 ioc_state;
7015 unsigned long time_count;
7016
7017 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n",
7018 ioc->name));
7019
7020 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
7021
7022 if (mpt_fwfault_debug)
7023 mpt_halt_firmware(ioc);
7024
7025 if (ioc_state == MPI_IOC_STATE_FAULT ||
7026 ioc_state == MPI_IOC_STATE_RESET) {
7027 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7028 "skipping, either in FAULT or RESET state!\n", ioc->name));
7029 return -1;
7030 }
7031
7032 if (ioc->bus_type == FC) {
7033 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7034 "skipping, because the bus type is FC!\n", ioc->name));
7035 return -1;
7036 }
7037
7038 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7039 if (ioc->ioc_reset_in_progress) {
7040 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7041 return -1;
7042 }
7043 ioc->ioc_reset_in_progress = 1;
7044 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7045
7046 rc = -1;
7047
7048 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7049 if (MptResetHandlers[cb_idx])
7050 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
7051 }
7052
7053 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7054 if (ioc->taskmgmt_in_progress) {
Kashyap, Desaib9a0f872010-06-17 14:42:39 +05307055 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05307056 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7057 return -1;
7058 }
7059 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7060 /* Disable reply interrupts (also blocks FreeQ) */
7061 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
7062 ioc->active = 0;
7063 time_count = jiffies;
7064
7065 rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
7066
7067 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7068 if (MptResetHandlers[cb_idx])
7069 mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
7070 }
7071
7072 if (rc)
7073 goto out;
7074
7075 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
7076 if (ioc_state != MPI_IOC_STATE_READY)
7077 goto out;
7078
7079 for (ii = 0; ii < 5; ii++) {
7080 /* Get IOC facts! Allow 5 retries */
7081 rc = GetIocFacts(ioc, sleepFlag,
7082 MPT_HOSTEVENT_IOC_RECOVER);
7083 if (rc == 0)
7084 break;
7085 if (sleepFlag == CAN_SLEEP)
7086 msleep(100);
7087 else
7088 mdelay(100);
7089 }
7090 if (ii == 5)
7091 goto out;
7092
7093 rc = PrimeIocFifos(ioc);
7094 if (rc != 0)
7095 goto out;
7096
7097 rc = SendIocInit(ioc, sleepFlag);
7098 if (rc != 0)
7099 goto out;
7100
7101 rc = SendEventNotification(ioc, 1, sleepFlag);
7102 if (rc != 0)
7103 goto out;
7104
7105 if (ioc->hard_resets < -1)
7106 ioc->hard_resets++;
7107
7108 /*
7109 * At this point, we know soft reset succeeded.
7110 */
7111
7112 ioc->active = 1;
7113 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
7114
7115 out:
7116 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7117 ioc->ioc_reset_in_progress = 0;
7118 ioc->taskmgmt_quiesce_io = 0;
7119 ioc->taskmgmt_in_progress = 0;
7120 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7121
7122 if (ioc->active) { /* otherwise, hard reset coming */
7123 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7124 if (MptResetHandlers[cb_idx])
7125 mpt_signal_reset(cb_idx, ioc,
7126 MPT_IOC_POST_RESET);
7127 }
7128 }
7129
7130 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7131 "SoftResetHandler: completed (%d seconds): %s\n",
7132 ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,
7133 ((rc == 0) ? "SUCCESS" : "FAILED")));
7134
7135 return rc;
7136}
7137
7138/**
7139 * mpt_Soft_Hard_ResetHandler - Try less expensive reset
7140 * @ioc: Pointer to MPT_ADAPTER structure
7141 * @sleepFlag: Indicates if sleep or schedule must be called.
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05307142 *
7143 * Returns 0 for SUCCESS or -1 if FAILED.
7144 * Try for softreset first, only if it fails go for expensive
7145 * HardReset.
7146 **/
7147int
7148mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag) {
7149 int ret = -1;
7150
7151 ret = mpt_SoftResetHandler(ioc, sleepFlag);
7152 if (ret == 0)
7153 return ret;
7154 ret = mpt_HardResetHandler(ioc, sleepFlag);
7155 return ret;
7156}
7157EXPORT_SYMBOL(mpt_Soft_Hard_ResetHandler);
7158
Linus Torvalds1da177e2005-04-16 15:20:36 -07007159/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7160/*
7161 * Reset Handling
7162 */
7163/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7164/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007165 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07007166 * @ioc: Pointer to MPT_ADAPTER structure
7167 * @sleepFlag: Indicates if sleep or schedule must be called.
7168 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007169 * Issues SCSI Task Management call based on input arg values.
7170 * If TaskMgmt fails, returns associated SCSI request.
7171 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07007172 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
7173 * or a non-interrupt thread. In the former, must not call schedule().
7174 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007175 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07007176 * FW reload/initialization failed.
7177 *
7178 * Returns 0 for SUCCESS or -1 if FAILED.
7179 */
7180int
7181mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
7182{
Kashyap, Desaid1306912009-08-05 12:53:51 +05307183 int rc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307184 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007185 unsigned long flags;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307186 unsigned long time_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007187
Prakash, Sathya436ace72007-07-24 15:42:08 +05307188 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007189#ifdef MFCNT
7190 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
7191 printk("MF count 0x%x !\n", ioc->mfcnt);
7192#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05307193 if (mpt_fwfault_debug)
7194 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007195
7196 /* Reset the adapter. Prevent more than 1 call to
7197 * mpt_do_ioc_recovery at any instant in time.
7198 */
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307199 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7200 if (ioc->ioc_reset_in_progress) {
7201 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05307202 ioc->wait_on_reset_completion = 1;
7203 do {
7204 ssleep(1);
7205 } while (ioc->ioc_reset_in_progress == 1);
7206 ioc->wait_on_reset_completion = 0;
7207 return ioc->reset_status;
7208 }
7209 if (ioc->wait_on_reset_completion) {
7210 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7211 rc = 0;
7212 time_count = jiffies;
7213 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007214 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307215 ioc->ioc_reset_in_progress = 1;
7216 if (ioc->alt_ioc)
7217 ioc->alt_ioc->ioc_reset_in_progress = 1;
7218 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007219
Linus Torvalds1da177e2005-04-16 15:20:36 -07007220
7221 /* The SCSI driver needs to adjust timeouts on all current
7222 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02007223 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007224 * For all other protocol drivers, this is a no-op.
7225 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05307226 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7227 if (MptResetHandlers[cb_idx]) {
7228 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
7229 if (ioc->alt_ioc)
7230 mpt_signal_reset(cb_idx, ioc->alt_ioc,
7231 MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007232 }
7233 }
7234
Kashyap, Desai2f187862009-05-29 16:52:37 +05307235 time_count = jiffies;
7236 rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
7237 if (rc != 0) {
7238 printk(KERN_WARNING MYNAM
Kei Tokunaga97009a22010-06-22 19:01:51 +09007239 ": WARNING - (%d) Cannot recover %s, doorbell=0x%08x\n",
7240 rc, ioc->name, mpt_GetIocState(ioc, 0));
Kashyap, Desai2f187862009-05-29 16:52:37 +05307241 } else {
7242 if (ioc->hard_resets < -1)
7243 ioc->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007244 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007245
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307246 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7247 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307248 ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307249 ioc->taskmgmt_in_progress = 0;
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05307250 ioc->reset_status = rc;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307251 if (ioc->alt_ioc) {
7252 ioc->alt_ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307253 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307254 ioc->alt_ioc->taskmgmt_in_progress = 0;
7255 }
7256 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007257
Kashyap, Desaid1306912009-08-05 12:53:51 +05307258 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7259 if (MptResetHandlers[cb_idx]) {
7260 mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
7261 if (ioc->alt_ioc)
7262 mpt_signal_reset(cb_idx,
7263 ioc->alt_ioc, MPT_IOC_POST_RESET);
7264 }
7265 }
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05307266exit:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307267 dtmprintk(ioc,
7268 printk(MYIOC_s_DEBUG_FMT
7269 "HardResetHandler: completed (%d seconds): %s\n", ioc->name,
7270 jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?
7271 "SUCCESS" : "FAILED")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007272
7273 return rc;
7274}
7275
Kashyap, Desai2f187862009-05-29 16:52:37 +05307276#ifdef CONFIG_FUSION_LOGGING
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007277static void
Kashyap, Desai2f187862009-05-29 16:52:37 +05307278mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007279{
Eric Moore509e5e52006-04-26 13:22:37 -06007280 char *ds = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307281 u32 evData0;
7282 int ii;
7283 u8 event;
7284 char *evStr = ioc->evStr;
7285
7286 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7287 evData0 = le32_to_cpu(pEventReply->Data[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007288
7289 switch(event) {
7290 case MPI_EVENT_NONE:
7291 ds = "None";
7292 break;
7293 case MPI_EVENT_LOG_DATA:
7294 ds = "Log Data";
7295 break;
7296 case MPI_EVENT_STATE_CHANGE:
7297 ds = "State Change";
7298 break;
7299 case MPI_EVENT_UNIT_ATTENTION:
7300 ds = "Unit Attention";
7301 break;
7302 case MPI_EVENT_IOC_BUS_RESET:
7303 ds = "IOC Bus Reset";
7304 break;
7305 case MPI_EVENT_EXT_BUS_RESET:
7306 ds = "External Bus Reset";
7307 break;
7308 case MPI_EVENT_RESCAN:
7309 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007310 break;
7311 case MPI_EVENT_LINK_STATUS_CHANGE:
7312 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
7313 ds = "Link Status(FAILURE) Change";
7314 else
7315 ds = "Link Status(ACTIVE) Change";
7316 break;
7317 case MPI_EVENT_LOOP_STATE_CHANGE:
7318 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
7319 ds = "Loop State(LIP) Change";
7320 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Kashyap, Desai2f187862009-05-29 16:52:37 +05307321 ds = "Loop State(LPE) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007322 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05307323 ds = "Loop State(LPB) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007324 break;
7325 case MPI_EVENT_LOGOUT:
7326 ds = "Logout";
7327 break;
7328 case MPI_EVENT_EVENT_CHANGE:
7329 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06007330 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007331 else
Eric Moore4f766dc2006-07-11 17:24:07 -06007332 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007333 break;
7334 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007335 {
7336 u8 ReasonCode = (u8)(evData0 >> 16);
7337 switch (ReasonCode) {
7338 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
7339 ds = "Integrated Raid: Volume Created";
7340 break;
7341 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
7342 ds = "Integrated Raid: Volume Deleted";
7343 break;
7344 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
7345 ds = "Integrated Raid: Volume Settings Changed";
7346 break;
7347 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
7348 ds = "Integrated Raid: Volume Status Changed";
7349 break;
7350 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
7351 ds = "Integrated Raid: Volume Physdisk Changed";
7352 break;
7353 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
7354 ds = "Integrated Raid: Physdisk Created";
7355 break;
7356 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
7357 ds = "Integrated Raid: Physdisk Deleted";
7358 break;
7359 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
7360 ds = "Integrated Raid: Physdisk Settings Changed";
7361 break;
7362 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
7363 ds = "Integrated Raid: Physdisk Status Changed";
7364 break;
7365 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
7366 ds = "Integrated Raid: Domain Validation Needed";
7367 break;
7368 case MPI_EVENT_RAID_RC_SMART_DATA :
7369 ds = "Integrated Raid; Smart Data";
7370 break;
7371 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
7372 ds = "Integrated Raid: Replace Action Started";
7373 break;
7374 default:
7375 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007376 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007377 }
7378 break;
7379 }
7380 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
7381 ds = "SCSI Device Status Change";
7382 break;
7383 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
7384 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007385 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007386 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007387 u8 ReasonCode = (u8)(evData0 >> 16);
7388 switch (ReasonCode) {
7389 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
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: Added: "
7392 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007393 break;
7394 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
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: Deleted: "
7397 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007398 break;
7399 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
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: SMART Data: "
7402 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007403 break;
7404 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007405 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007406 "SAS Device Status Change: No Persistancy: "
7407 "id=%d channel=%d", id, channel);
7408 break;
7409 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
7410 snprintf(evStr, EVENT_DESCR_STR_SZ,
7411 "SAS Device Status Change: Unsupported Device "
7412 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007413 break;
7414 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
7415 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007416 "SAS Device Status Change: Internal Device "
7417 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007418 break;
7419 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
7420 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007421 "SAS Device Status Change: Internal Task "
7422 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007423 break;
7424 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
7425 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007426 "SAS Device Status Change: Internal Abort "
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_CLEAR_TASK_SET_INTERNAL:
7430 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007431 "SAS Device Status Change: Internal Clear "
7432 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007433 break;
7434 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
7435 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007436 "SAS Device Status Change: Internal Query "
7437 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007438 break;
7439 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007440 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007441 "SAS Device Status Change: Unknown: "
7442 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06007443 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007444 }
7445 break;
7446 }
7447 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
7448 ds = "Bus Timer Expired";
7449 break;
7450 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07007451 {
7452 u16 curr_depth = (u16)(evData0 >> 16);
7453 u8 channel = (u8)(evData0 >> 8);
7454 u8 id = (u8)(evData0);
7455
7456 snprintf(evStr, EVENT_DESCR_STR_SZ,
7457 "Queue Full: channel=%d id=%d depth=%d",
7458 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007459 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07007460 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007461 case MPI_EVENT_SAS_SES:
7462 ds = "SAS SES Event";
7463 break;
7464 case MPI_EVENT_PERSISTENT_TABLE_FULL:
7465 ds = "Persistent Table Full";
7466 break;
7467 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07007468 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007469 u8 LinkRates = (u8)(evData0 >> 8);
7470 u8 PhyNumber = (u8)(evData0);
7471 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
7472 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
7473 switch (LinkRates) {
7474 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
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 " Rate Unknown",PhyNumber);
7478 break;
7479 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
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 " Phy Disabled",PhyNumber);
7483 break;
7484 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
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 " Failed Speed Nego",PhyNumber);
7488 break;
7489 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
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 " Sata OOB Completed",PhyNumber);
7493 break;
7494 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06007495 snprintf(evStr, EVENT_DESCR_STR_SZ,
7496 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007497 " Rate 1.5 Gbps",PhyNumber);
7498 break;
7499 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06007500 snprintf(evStr, EVENT_DESCR_STR_SZ,
7501 "SAS PHY Link Status: Phy=%d:"
Kashyap, Desaid75733d2011-02-10 11:50:39 +05307502 " Rate 3.0 Gbps", PhyNumber);
7503 break;
7504 case MPI_EVENT_SAS_PLS_LR_RATE_6_0:
7505 snprintf(evStr, EVENT_DESCR_STR_SZ,
7506 "SAS PHY Link Status: Phy=%d:"
7507 " Rate 6.0 Gbps", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007508 break;
7509 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007510 snprintf(evStr, EVENT_DESCR_STR_SZ,
7511 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007512 break;
7513 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007514 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007515 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007516 case MPI_EVENT_SAS_DISCOVERY_ERROR:
7517 ds = "SAS Discovery Error";
7518 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007519 case MPI_EVENT_IR_RESYNC_UPDATE:
7520 {
7521 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06007522 snprintf(evStr, EVENT_DESCR_STR_SZ,
7523 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07007524 break;
7525 }
7526 case MPI_EVENT_IR2:
7527 {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307528 u8 id = (u8)(evData0);
7529 u8 channel = (u8)(evData0 >> 8);
7530 u8 phys_num = (u8)(evData0 >> 24);
Moore, Eric3a892be2006-03-14 09:14:03 -07007531 u8 ReasonCode = (u8)(evData0 >> 16);
Kashyap, Desai2f187862009-05-29 16:52:37 +05307532
Moore, Eric3a892be2006-03-14 09:14:03 -07007533 switch (ReasonCode) {
7534 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307535 snprintf(evStr, EVENT_DESCR_STR_SZ,
7536 "IR2: LD State Changed: "
7537 "id=%d channel=%d phys_num=%d",
7538 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007539 break;
7540 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307541 snprintf(evStr, EVENT_DESCR_STR_SZ,
7542 "IR2: PD State Changed "
7543 "id=%d channel=%d phys_num=%d",
7544 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007545 break;
7546 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307547 snprintf(evStr, EVENT_DESCR_STR_SZ,
7548 "IR2: Bad Block Table Full: "
7549 "id=%d channel=%d phys_num=%d",
7550 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007551 break;
7552 case MPI_EVENT_IR2_RC_PD_INSERTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307553 snprintf(evStr, EVENT_DESCR_STR_SZ,
7554 "IR2: PD Inserted: "
7555 "id=%d channel=%d phys_num=%d",
7556 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007557 break;
7558 case MPI_EVENT_IR2_RC_PD_REMOVED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307559 snprintf(evStr, EVENT_DESCR_STR_SZ,
7560 "IR2: PD Removed: "
7561 "id=%d channel=%d phys_num=%d",
7562 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007563 break;
7564 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307565 snprintf(evStr, EVENT_DESCR_STR_SZ,
7566 "IR2: Foreign CFG Detected: "
7567 "id=%d channel=%d phys_num=%d",
7568 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007569 break;
7570 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307571 snprintf(evStr, EVENT_DESCR_STR_SZ,
7572 "IR2: Rebuild Medium Error: "
7573 "id=%d channel=%d phys_num=%d",
7574 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007575 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05307576 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
7577 snprintf(evStr, EVENT_DESCR_STR_SZ,
7578 "IR2: Dual Port Added: "
7579 "id=%d channel=%d phys_num=%d",
7580 id, channel, phys_num);
7581 break;
7582 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
7583 snprintf(evStr, EVENT_DESCR_STR_SZ,
7584 "IR2: Dual Port Removed: "
7585 "id=%d channel=%d phys_num=%d",
7586 id, channel, phys_num);
7587 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007588 default:
7589 ds = "IR2";
7590 break;
7591 }
7592 break;
7593 }
7594 case MPI_EVENT_SAS_DISCOVERY:
7595 {
7596 if (evData0)
7597 ds = "SAS Discovery: Start";
7598 else
7599 ds = "SAS Discovery: Stop";
7600 break;
7601 }
7602 case MPI_EVENT_LOG_ENTRY_ADDED:
7603 ds = "SAS Log Entry Added";
7604 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007605
Eric Moorec6c727a2007-01-29 09:44:54 -07007606 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
7607 {
7608 u8 phy_num = (u8)(evData0);
7609 u8 port_num = (u8)(evData0 >> 8);
7610 u8 port_width = (u8)(evData0 >> 16);
7611 u8 primative = (u8)(evData0 >> 24);
7612 snprintf(evStr, EVENT_DESCR_STR_SZ,
7613 "SAS Broadcase Primative: phy=%d port=%d "
7614 "width=%d primative=0x%02x",
7615 phy_num, port_num, port_width, primative);
7616 break;
7617 }
7618
7619 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7620 {
7621 u8 reason = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007622
Kashyap, Desai2f187862009-05-29 16:52:37 +05307623 switch (reason) {
7624 case MPI_EVENT_SAS_INIT_RC_ADDED:
7625 ds = "SAS Initiator Status Change: Added";
7626 break;
7627 case MPI_EVENT_SAS_INIT_RC_REMOVED:
7628 ds = "SAS Initiator Status Change: Deleted";
7629 break;
7630 default:
7631 ds = "SAS Initiator Status Change";
7632 break;
7633 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007634 break;
7635 }
7636
7637 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7638 {
7639 u8 max_init = (u8)(evData0);
7640 u8 current_init = (u8)(evData0 >> 8);
7641
7642 snprintf(evStr, EVENT_DESCR_STR_SZ,
7643 "SAS Initiator Device Table Overflow: max initiators=%02d "
7644 "current initators=%02d",
7645 max_init, current_init);
7646 break;
7647 }
7648 case MPI_EVENT_SAS_SMP_ERROR:
7649 {
7650 u8 status = (u8)(evData0);
7651 u8 port_num = (u8)(evData0 >> 8);
7652 u8 result = (u8)(evData0 >> 16);
7653
7654 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7655 snprintf(evStr, EVENT_DESCR_STR_SZ,
7656 "SAS SMP Error: port=%d result=0x%02x",
7657 port_num, result);
7658 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7659 snprintf(evStr, EVENT_DESCR_STR_SZ,
7660 "SAS SMP Error: port=%d : CRC Error",
7661 port_num);
7662 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7663 snprintf(evStr, EVENT_DESCR_STR_SZ,
7664 "SAS SMP Error: port=%d : Timeout",
7665 port_num);
7666 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7667 snprintf(evStr, EVENT_DESCR_STR_SZ,
7668 "SAS SMP Error: port=%d : No Destination",
7669 port_num);
7670 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7671 snprintf(evStr, EVENT_DESCR_STR_SZ,
7672 "SAS SMP Error: port=%d : Bad Destination",
7673 port_num);
7674 else
7675 snprintf(evStr, EVENT_DESCR_STR_SZ,
7676 "SAS SMP Error: port=%d : status=0x%02x",
7677 port_num, status);
7678 break;
7679 }
7680
Kashyap, Desai2f187862009-05-29 16:52:37 +05307681 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
7682 {
7683 u8 reason = (u8)(evData0);
7684
7685 switch (reason) {
7686 case MPI_EVENT_SAS_EXP_RC_ADDED:
7687 ds = "Expander Status Change: Added";
7688 break;
7689 case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
7690 ds = "Expander Status Change: Deleted";
7691 break;
7692 default:
7693 ds = "Expander Status Change";
7694 break;
7695 }
7696 break;
7697 }
7698
Linus Torvalds1da177e2005-04-16 15:20:36 -07007699 /*
7700 * MPT base "custom" events may be added here...
7701 */
7702 default:
7703 ds = "Unknown";
7704 break;
7705 }
Eric Moore509e5e52006-04-26 13:22:37 -06007706 if (ds)
7707 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007708
Kashyap, Desai2f187862009-05-29 16:52:37 +05307709
7710 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7711 "MPT event:(%02Xh) : %s\n",
7712 ioc->name, event, evStr));
7713
7714 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
7715 ": Event data:\n"));
7716 for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
7717 devtverboseprintk(ioc, printk(" %08x",
7718 le32_to_cpu(pEventReply->Data[ii])));
7719 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
7720}
7721#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007722/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007723/**
7724 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007725 * @ioc: Pointer to MPT_ADAPTER structure
7726 * @pEventReply: Pointer to EventNotification reply frame
7727 * @evHandlers: Pointer to integer, number of event handlers
7728 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007729 * Routes a received EventNotificationReply to all currently registered
7730 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007731 * Returns sum of event handlers return values.
7732 */
7733static int
7734ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7735{
7736 u16 evDataLen;
7737 u32 evData0 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007738 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307739 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007740 int r = 0;
7741 int handlers = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007742 u8 event;
7743
7744 /*
7745 * Do platform normalization of values
7746 */
7747 event = le32_to_cpu(pEventReply->Event) & 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007748 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7749 if (evDataLen) {
7750 evData0 = le32_to_cpu(pEventReply->Data[0]);
7751 }
7752
Prakash, Sathya436ace72007-07-24 15:42:08 +05307753#ifdef CONFIG_FUSION_LOGGING
Kashyap, Desai2f187862009-05-29 16:52:37 +05307754 if (evDataLen)
7755 mpt_display_event_info(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007756#endif
7757
7758 /*
7759 * Do general / base driver event processing
7760 */
7761 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007762 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7763 if (evDataLen) {
7764 u8 evState = evData0 & 0xFF;
7765
7766 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7767
7768 /* Update EventState field in cached IocFacts */
7769 if (ioc->facts.Function) {
7770 ioc->facts.EventState = evState;
7771 }
7772 }
7773 break;
Moore, Ericece50912006-01-16 18:53:19 -07007774 case MPI_EVENT_INTEGRATED_RAID:
7775 mptbase_raid_process_event_data(ioc,
7776 (MpiEventDataRaid_t *)pEventReply->Data);
7777 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007778 default:
7779 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007780 }
7781
7782 /*
7783 * Should this event be logged? Events are written sequentially.
7784 * When buffer is full, start again at the top.
7785 */
7786 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7787 int idx;
7788
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007789 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007790
7791 ioc->events[idx].event = event;
7792 ioc->events[idx].eventContext = ioc->eventContext;
7793
7794 for (ii = 0; ii < 2; ii++) {
7795 if (ii < evDataLen)
7796 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7797 else
7798 ioc->events[idx].data[ii] = 0;
7799 }
7800
7801 ioc->eventContext++;
7802 }
7803
7804
7805 /*
7806 * Call each currently registered protocol event handler.
7807 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007808 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307809 if (MptEvHandlers[cb_idx]) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307810 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7811 "Routing Event to event handler #%d\n",
7812 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307813 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007814 handlers++;
7815 }
7816 }
7817 /* FIXME? Examine results here? */
7818
7819 /*
7820 * If needed, send (a single) EventAck.
7821 */
7822 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307823 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007824 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007825 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307826 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007827 ioc->name, ii));
7828 }
7829 }
7830
7831 *evHandlers = handlers;
7832 return r;
7833}
7834
7835/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007836/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007837 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7838 * @ioc: Pointer to MPT_ADAPTER structure
7839 * @log_info: U32 LogInfo reply word from the IOC
7840 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007841 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007842 */
7843static void
7844mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7845{
Eric Moore7c431e52007-06-13 16:34:36 -06007846 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007847
Eric Moore7c431e52007-06-13 16:34:36 -06007848 switch (log_info & 0xFF000000) {
7849 case MPI_IOCLOGINFO_FC_INIT_BASE:
7850 desc = "FCP Initiator";
7851 break;
7852 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7853 desc = "FCP Target";
7854 break;
7855 case MPI_IOCLOGINFO_FC_LAN_BASE:
7856 desc = "LAN";
7857 break;
7858 case MPI_IOCLOGINFO_FC_MSG_BASE:
7859 desc = "MPI Message Layer";
7860 break;
7861 case MPI_IOCLOGINFO_FC_LINK_BASE:
7862 desc = "FC Link";
7863 break;
7864 case MPI_IOCLOGINFO_FC_CTX_BASE:
7865 desc = "Context Manager";
7866 break;
7867 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7868 desc = "Invalid Field Offset";
7869 break;
7870 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7871 desc = "State Change Info";
7872 break;
7873 }
7874
7875 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7876 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007877}
7878
7879/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007880/**
Moore, Eric335a9412006-01-17 17:06:23 -07007881 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007882 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007883 * @log_info: U32 LogInfo word from the IOC
7884 *
7885 * Refer to lsi/sp_log.h.
7886 */
7887static void
Moore, Eric335a9412006-01-17 17:06:23 -07007888mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007889{
7890 u32 info = log_info & 0x00FF0000;
7891 char *desc = "unknown";
7892
7893 switch (info) {
7894 case 0x00010000:
7895 desc = "bug! MID not found";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007896 break;
7897
7898 case 0x00020000:
7899 desc = "Parity Error";
7900 break;
7901
7902 case 0x00030000:
7903 desc = "ASYNC Outbound Overrun";
7904 break;
7905
7906 case 0x00040000:
7907 desc = "SYNC Offset Error";
7908 break;
7909
7910 case 0x00050000:
7911 desc = "BM Change";
7912 break;
7913
7914 case 0x00060000:
7915 desc = "Msg In Overflow";
7916 break;
7917
7918 case 0x00070000:
7919 desc = "DMA Error";
7920 break;
7921
7922 case 0x00080000:
7923 desc = "Outbound DMA Overrun";
7924 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007925
Linus Torvalds1da177e2005-04-16 15:20:36 -07007926 case 0x00090000:
7927 desc = "Task Management";
7928 break;
7929
7930 case 0x000A0000:
7931 desc = "Device Problem";
7932 break;
7933
7934 case 0x000B0000:
7935 desc = "Invalid Phase Change";
7936 break;
7937
7938 case 0x000C0000:
7939 desc = "Untagged Table Size";
7940 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007941
Linus Torvalds1da177e2005-04-16 15:20:36 -07007942 }
7943
7944 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7945}
7946
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007947/* strings for sas loginfo */
7948 static char *originator_str[] = {
7949 "IOP", /* 00h */
7950 "PL", /* 01h */
7951 "IR" /* 02h */
7952 };
7953 static char *iop_code_str[] = {
7954 NULL, /* 00h */
7955 "Invalid SAS Address", /* 01h */
7956 NULL, /* 02h */
7957 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007958 "Diag Message Error", /* 04h */
7959 "Task Terminated", /* 05h */
7960 "Enclosure Management", /* 06h */
7961 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007962 };
7963 static char *pl_code_str[] = {
7964 NULL, /* 00h */
7965 "Open Failure", /* 01h */
7966 "Invalid Scatter Gather List", /* 02h */
7967 "Wrong Relative Offset or Frame Length", /* 03h */
7968 "Frame Transfer Error", /* 04h */
7969 "Transmit Frame Connected Low", /* 05h */
7970 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7971 "SATA Read Log Receive Data Error", /* 07h */
7972 "SATA NCQ Fail All Commands After Error", /* 08h */
7973 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7974 "Receive Frame Invalid Message", /* 0Ah */
7975 "Receive Context Message Valid Error", /* 0Bh */
7976 "Receive Frame Current Frame Error", /* 0Ch */
7977 "SATA Link Down", /* 0Dh */
7978 "Discovery SATA Init W IOS", /* 0Eh */
7979 "Config Invalid Page", /* 0Fh */
7980 "Discovery SATA Init Timeout", /* 10h */
7981 "Reset", /* 11h */
7982 "Abort", /* 12h */
7983 "IO Not Yet Executed", /* 13h */
7984 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007985 "Persistent Reservation Out Not Affiliation "
7986 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007987 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007988 "IO Device Missing Delay Retry", /* 17h */
Lucas De Marchi25985ed2011-03-30 22:57:33 -03007989 "IO Cancelled Due to Receive Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007990 NULL, /* 19h */
7991 NULL, /* 1Ah */
7992 NULL, /* 1Bh */
7993 NULL, /* 1Ch */
7994 NULL, /* 1Dh */
7995 NULL, /* 1Eh */
7996 NULL, /* 1Fh */
7997 "Enclosure Management" /* 20h */
7998 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007999 static char *ir_code_str[] = {
8000 "Raid Action Error", /* 00h */
8001 NULL, /* 00h */
8002 NULL, /* 01h */
8003 NULL, /* 02h */
8004 NULL, /* 03h */
8005 NULL, /* 04h */
8006 NULL, /* 05h */
8007 NULL, /* 06h */
8008 NULL /* 07h */
8009 };
8010 static char *raid_sub_code_str[] = {
8011 NULL, /* 00h */
8012 "Volume Creation Failed: Data Passed too "
8013 "Large", /* 01h */
8014 "Volume Creation Failed: Duplicate Volumes "
8015 "Attempted", /* 02h */
8016 "Volume Creation Failed: Max Number "
8017 "Supported Volumes Exceeded", /* 03h */
8018 "Volume Creation Failed: DMA Error", /* 04h */
8019 "Volume Creation Failed: Invalid Volume Type", /* 05h */
8020 "Volume Creation Failed: Error Reading "
8021 "MFG Page 4", /* 06h */
8022 "Volume Creation Failed: Creating Internal "
8023 "Structures", /* 07h */
8024 NULL, /* 08h */
8025 NULL, /* 09h */
8026 NULL, /* 0Ah */
8027 NULL, /* 0Bh */
8028 NULL, /* 0Ch */
8029 NULL, /* 0Dh */
8030 NULL, /* 0Eh */
8031 NULL, /* 0Fh */
8032 "Activation failed: Already Active Volume", /* 10h */
8033 "Activation failed: Unsupported Volume Type", /* 11h */
8034 "Activation failed: Too Many Active Volumes", /* 12h */
8035 "Activation failed: Volume ID in Use", /* 13h */
8036 "Activation failed: Reported Failure", /* 14h */
8037 "Activation failed: Importing a Volume", /* 15h */
8038 NULL, /* 16h */
8039 NULL, /* 17h */
8040 NULL, /* 18h */
8041 NULL, /* 19h */
8042 NULL, /* 1Ah */
8043 NULL, /* 1Bh */
8044 NULL, /* 1Ch */
8045 NULL, /* 1Dh */
8046 NULL, /* 1Eh */
8047 NULL, /* 1Fh */
8048 "Phys Disk failed: Too Many Phys Disks", /* 20h */
8049 "Phys Disk failed: Data Passed too Large", /* 21h */
8050 "Phys Disk failed: DMA Error", /* 22h */
8051 "Phys Disk failed: Invalid <channel:id>", /* 23h */
8052 "Phys Disk failed: Creating Phys Disk Config "
8053 "Page", /* 24h */
8054 NULL, /* 25h */
8055 NULL, /* 26h */
8056 NULL, /* 27h */
8057 NULL, /* 28h */
8058 NULL, /* 29h */
8059 NULL, /* 2Ah */
8060 NULL, /* 2Bh */
8061 NULL, /* 2Ch */
8062 NULL, /* 2Dh */
8063 NULL, /* 2Eh */
8064 NULL, /* 2Fh */
8065 "Compatibility Error: IR Disabled", /* 30h */
Uwe Kleine-Königb5950762010-11-01 15:38:34 -04008066 "Compatibility Error: Inquiry Command Failed", /* 31h */
Eric Moorec6c727a2007-01-29 09:44:54 -07008067 "Compatibility Error: Device not Direct Access "
8068 "Device ", /* 32h */
8069 "Compatibility Error: Removable Device Found", /* 33h */
8070 "Compatibility Error: Device SCSI Version not "
8071 "2 or Higher", /* 34h */
8072 "Compatibility Error: SATA Device, 48 BIT LBA "
8073 "not Supported", /* 35h */
8074 "Compatibility Error: Device doesn't have "
8075 "512 Byte Block Sizes", /* 36h */
8076 "Compatibility Error: Volume Type Check Failed", /* 37h */
8077 "Compatibility Error: Volume Type is "
8078 "Unsupported by FW", /* 38h */
8079 "Compatibility Error: Disk Drive too Small for "
8080 "use in Volume", /* 39h */
8081 "Compatibility Error: Phys Disk for Create "
8082 "Volume not Found", /* 3Ah */
8083 "Compatibility Error: Too Many or too Few "
8084 "Disks for Volume Type", /* 3Bh */
8085 "Compatibility Error: Disk stripe Sizes "
8086 "Must be 64KB", /* 3Ch */
8087 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
8088 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008089
8090/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008091/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008092 * mpt_sas_log_info - Log information returned from SAS IOC.
8093 * @ioc: Pointer to MPT_ADAPTER structure
8094 * @log_info: U32 LogInfo reply word from the IOC
Randy Dunlapfc58fb12010-08-14 13:05:57 -07008095 * @cb_idx: callback function's handle
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008096 *
8097 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008098 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008099static void
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308100mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info, u8 cb_idx)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008101{
8102union loginfo_type {
8103 u32 loginfo;
8104 struct {
8105 u32 subcode:16;
8106 u32 code:8;
8107 u32 originator:4;
8108 u32 bus_type:4;
8109 }dw;
8110};
8111 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07008112 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008113 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07008114 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008115
8116 sas_loginfo.loginfo = log_info;
8117 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008118 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008119 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07008120
8121 originator_desc = originator_str[sas_loginfo.dw.originator];
8122
8123 switch (sas_loginfo.dw.originator) {
8124
8125 case 0: /* IOP */
8126 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008127 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008128 code_desc = iop_code_str[sas_loginfo.dw.code];
8129 break;
8130 case 1: /* PL */
8131 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008132 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008133 code_desc = pl_code_str[sas_loginfo.dw.code];
8134 break;
8135 case 2: /* IR */
8136 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008137 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008138 break;
8139 code_desc = ir_code_str[sas_loginfo.dw.code];
8140 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008141 ARRAY_SIZE(raid_sub_code_str))
Julia Lawall081f4f42010-08-05 22:27:14 +02008142 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07008143 if (sas_loginfo.dw.code == 0)
8144 sub_code_desc =
8145 raid_sub_code_str[sas_loginfo.dw.subcode];
8146 break;
8147 default:
8148 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008149 }
8150
Eric Moorec6c727a2007-01-29 09:44:54 -07008151 if (sub_code_desc != NULL)
8152 printk(MYIOC_s_INFO_FMT
8153 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308154 " SubCode={%s} cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008155 ioc->name, log_info, originator_desc, code_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308156 sub_code_desc, MptCallbacksName[cb_idx]);
Eric Moorec6c727a2007-01-29 09:44:54 -07008157 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008158 printk(MYIOC_s_INFO_FMT
8159 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308160 " SubCode(0x%04x) cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008161 ioc->name, log_info, originator_desc, code_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308162 sas_loginfo.dw.subcode, MptCallbacksName[cb_idx]);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008163 else
8164 printk(MYIOC_s_INFO_FMT
8165 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308166 " SubCode(0x%04x) cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008167 ioc->name, log_info, originator_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308168 sas_loginfo.dw.code, sas_loginfo.dw.subcode,
8169 MptCallbacksName[cb_idx]);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008170}
8171
Linus Torvalds1da177e2005-04-16 15:20:36 -07008172/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008173/**
Eric Moorec6c727a2007-01-29 09:44:54 -07008174 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
8175 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08008176 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07008177 * @mf: Pointer to MPT request frame
8178 *
8179 * Refer to lsi/mpi.h.
8180 **/
8181static void
8182mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
8183{
8184 Config_t *pReq = (Config_t *)mf;
8185 char extend_desc[EVENT_DESCR_STR_SZ];
8186 char *desc = NULL;
8187 u32 form;
8188 u8 page_type;
8189
8190 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
8191 page_type = pReq->ExtPageType;
8192 else
8193 page_type = pReq->Header.PageType;
8194
8195 /*
8196 * ignore invalid page messages for GET_NEXT_HANDLE
8197 */
8198 form = le32_to_cpu(pReq->PageAddress);
8199 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
8200 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
8201 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
8202 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
8203 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
8204 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
8205 return;
8206 }
8207 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
8208 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
8209 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
8210 return;
8211 }
8212
8213 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
8214 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
8215 page_type, pReq->Header.PageNumber, pReq->Action, form);
8216
8217 switch (ioc_status) {
8218
8219 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8220 desc = "Config Page Invalid Action";
8221 break;
8222
8223 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8224 desc = "Config Page Invalid Type";
8225 break;
8226
8227 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8228 desc = "Config Page Invalid Page";
8229 break;
8230
8231 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8232 desc = "Config Page Invalid Data";
8233 break;
8234
8235 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8236 desc = "Config Page No Defaults";
8237 break;
8238
8239 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
8240 desc = "Config Page Can't Commit";
8241 break;
8242 }
8243
8244 if (!desc)
8245 return;
8246
Eric Moore29dd3602007-09-14 18:46:51 -06008247 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
8248 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07008249}
8250
8251/**
8252 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07008253 * @ioc: Pointer to MPT_ADAPTER structure
8254 * @ioc_status: U32 IOCStatus word from IOC
8255 * @mf: Pointer to MPT request frame
8256 *
8257 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008258 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07008259static void
Eric Moorec6c727a2007-01-29 09:44:54 -07008260mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008261{
8262 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06008263 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008264
8265 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07008266
8267/****************************************************************************/
8268/* Common IOCStatus values for all replies */
8269/****************************************************************************/
8270
Linus Torvalds1da177e2005-04-16 15:20:36 -07008271 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
8272 desc = "Invalid Function";
8273 break;
8274
8275 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
8276 desc = "Busy";
8277 break;
8278
8279 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
8280 desc = "Invalid SGL";
8281 break;
8282
8283 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
8284 desc = "Internal Error";
8285 break;
8286
8287 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
8288 desc = "Reserved";
8289 break;
8290
8291 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
8292 desc = "Insufficient Resources";
8293 break;
8294
8295 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
8296 desc = "Invalid Field";
8297 break;
8298
8299 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
8300 desc = "Invalid State";
8301 break;
8302
Eric Moorec6c727a2007-01-29 09:44:54 -07008303/****************************************************************************/
8304/* Config IOCStatus values */
8305/****************************************************************************/
8306
Linus Torvalds1da177e2005-04-16 15:20:36 -07008307 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8308 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8309 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8310 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8311 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8312 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008313 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008314 break;
8315
Eric Moorec6c727a2007-01-29 09:44:54 -07008316/****************************************************************************/
8317/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
8318/* */
8319/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
8320/* */
8321/****************************************************************************/
8322
Linus Torvalds1da177e2005-04-16 15:20:36 -07008323 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008324 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008325 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
8326 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
8327 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
8328 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008329 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008330 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008331 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008332 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008333 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008334 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07008335 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008336 break;
8337
Eric Moorec6c727a2007-01-29 09:44:54 -07008338/****************************************************************************/
8339/* SCSI Target values */
8340/****************************************************************************/
8341
8342 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
8343 desc = "Target: Priority IO";
8344 break;
8345
8346 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
8347 desc = "Target: Invalid Port";
8348 break;
8349
8350 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
8351 desc = "Target Invalid IO Index:";
8352 break;
8353
8354 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
8355 desc = "Target: Aborted";
8356 break;
8357
8358 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
8359 desc = "Target: No Conn Retryable";
8360 break;
8361
8362 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
8363 desc = "Target: No Connection";
8364 break;
8365
8366 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
8367 desc = "Target: Transfer Count Mismatch";
8368 break;
8369
8370 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
8371 desc = "Target: STS Data not Sent";
8372 break;
8373
8374 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
8375 desc = "Target: Data Offset Error";
8376 break;
8377
8378 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
8379 desc = "Target: Too Much Write Data";
8380 break;
8381
8382 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
8383 desc = "Target: IU Too Short";
8384 break;
8385
8386 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
8387 desc = "Target: ACK NAK Timeout";
8388 break;
8389
8390 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
8391 desc = "Target: Nak Received";
8392 break;
8393
8394/****************************************************************************/
8395/* Fibre Channel Direct Access values */
8396/****************************************************************************/
8397
8398 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
8399 desc = "FC: Aborted";
8400 break;
8401
8402 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
8403 desc = "FC: RX ID Invalid";
8404 break;
8405
8406 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
8407 desc = "FC: DID Invalid";
8408 break;
8409
8410 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
8411 desc = "FC: Node Logged Out";
8412 break;
8413
8414 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
8415 desc = "FC: Exchange Canceled";
8416 break;
8417
8418/****************************************************************************/
8419/* LAN values */
8420/****************************************************************************/
8421
8422 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
8423 desc = "LAN: Device not Found";
8424 break;
8425
8426 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
8427 desc = "LAN: Device Failure";
8428 break;
8429
8430 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
8431 desc = "LAN: Transmit Error";
8432 break;
8433
8434 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
8435 desc = "LAN: Transmit Aborted";
8436 break;
8437
8438 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
8439 desc = "LAN: Receive Error";
8440 break;
8441
8442 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
8443 desc = "LAN: Receive Aborted";
8444 break;
8445
8446 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
8447 desc = "LAN: Partial Packet";
8448 break;
8449
8450 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
8451 desc = "LAN: Canceled";
8452 break;
8453
8454/****************************************************************************/
8455/* Serial Attached SCSI values */
8456/****************************************************************************/
8457
8458 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
8459 desc = "SAS: SMP Request Failed";
8460 break;
8461
8462 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
8463 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07008464 break;
8465
8466 default:
8467 desc = "Others";
8468 break;
8469 }
Eric Moorec6c727a2007-01-29 09:44:54 -07008470
8471 if (!desc)
8472 return;
8473
Eric Moore29dd3602007-09-14 18:46:51 -06008474 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
8475 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008476}
8477
8478/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008479EXPORT_SYMBOL(mpt_attach);
8480EXPORT_SYMBOL(mpt_detach);
8481#ifdef CONFIG_PM
8482EXPORT_SYMBOL(mpt_resume);
8483EXPORT_SYMBOL(mpt_suspend);
8484#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07008485EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008486EXPORT_SYMBOL(mpt_register);
8487EXPORT_SYMBOL(mpt_deregister);
8488EXPORT_SYMBOL(mpt_event_register);
8489EXPORT_SYMBOL(mpt_event_deregister);
8490EXPORT_SYMBOL(mpt_reset_register);
8491EXPORT_SYMBOL(mpt_reset_deregister);
8492EXPORT_SYMBOL(mpt_device_driver_register);
8493EXPORT_SYMBOL(mpt_device_driver_deregister);
8494EXPORT_SYMBOL(mpt_get_msg_frame);
8495EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05308496EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008497EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008498EXPORT_SYMBOL(mpt_send_handshake_request);
8499EXPORT_SYMBOL(mpt_verify_adapter);
8500EXPORT_SYMBOL(mpt_GetIocState);
8501EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008502EXPORT_SYMBOL(mpt_HardResetHandler);
8503EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008504EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008505EXPORT_SYMBOL(mpt_alloc_fw_memory);
8506EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02008507EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07008508EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008509
Linus Torvalds1da177e2005-04-16 15:20:36 -07008510/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008511/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008512 * fusion_init - Fusion MPT base driver initialization routine.
8513 *
8514 * Returns 0 for success, non-zero for failure.
8515 */
8516static int __init
8517fusion_init(void)
8518{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308519 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008520
8521 show_mptmod_ver(my_NAME, my_VERSION);
8522 printk(KERN_INFO COPYRIGHT "\n");
8523
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308524 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
8525 MptCallbacks[cb_idx] = NULL;
8526 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
8527 MptEvHandlers[cb_idx] = NULL;
8528 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008529 }
8530
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008531 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07008532 * EventNotification handling.
8533 */
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308534 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER,
8535 "mptbase_reply");
Linus Torvalds1da177e2005-04-16 15:20:36 -07008536
8537 /* Register for hard reset handling callbacks.
8538 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05308539 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008540
8541#ifdef CONFIG_PROC_FS
8542 (void) procmpt_create();
8543#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008544 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008545}
8546
8547/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008548/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008549 * fusion_exit - Perform driver unload cleanup.
8550 *
8551 * This routine frees all resources associated with each MPT adapter
8552 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
8553 */
8554static void __exit
8555fusion_exit(void)
8556{
8557
Linus Torvalds1da177e2005-04-16 15:20:36 -07008558 mpt_reset_deregister(mpt_base_index);
8559
8560#ifdef CONFIG_PROC_FS
8561 procmpt_destroy();
8562#endif
8563}
8564
Linus Torvalds1da177e2005-04-16 15:20:36 -07008565module_init(fusion_init);
8566module_exit(fusion_exit);