blob: 1cdab6d00b43493c36c151e4bb94b82b1d281f10 [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>
kashyap.desai@lsi.come62cca12011-08-04 16:42:15 +053062#include <linux/kthread.h>
63#include <scsi/scsi_host.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65#include "mptbase.h"
Eric Moore7c431e52007-06-13 16:34:36 -060066#include "lsi/mpi_log_fc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
68/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
69#define my_NAME "Fusion MPT base driver"
70#define my_VERSION MPT_LINUX_VERSION_COMMON
71#define MYNAM "mptbase"
72
73MODULE_AUTHOR(MODULEAUTHOR);
74MODULE_DESCRIPTION(my_NAME);
75MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070076MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
78/*
79 * cmd line parameters
80 */
Kashyap, Desaie3829682009-01-08 14:27:16 +053081
82static int mpt_msi_enable_spi;
83module_param(mpt_msi_enable_spi, int, 0);
Joe Perches85ee7a12011-04-23 20:38:19 -070084MODULE_PARM_DESC(mpt_msi_enable_spi,
85 " Enable MSI Support for SPI controllers (default=0)");
Kashyap, Desaie3829682009-01-08 14:27:16 +053086
87static int mpt_msi_enable_fc;
88module_param(mpt_msi_enable_fc, int, 0);
Joe Perches85ee7a12011-04-23 20:38:19 -070089MODULE_PARM_DESC(mpt_msi_enable_fc,
90 " Enable MSI Support for FC controllers (default=0)");
Kashyap, Desaie3829682009-01-08 14:27:16 +053091
92static int mpt_msi_enable_sas;
Yinghai Lu5ce78682009-02-18 11:25:32 -080093module_param(mpt_msi_enable_sas, int, 0);
Joe Perches85ee7a12011-04-23 20:38:19 -070094MODULE_PARM_DESC(mpt_msi_enable_sas,
95 " Enable MSI Support for SAS controllers (default=0)");
Christoph Hellwig4ddce142006-01-17 13:44:29 +000096
Eric Moore793955f2007-01-29 09:42:20 -070097static int mpt_channel_mapping;
98module_param(mpt_channel_mapping, int, 0);
99MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
100
Prakash, Sathya436ace72007-07-24 15:42:08 +0530101static int mpt_debug_level;
Kees Cook24da2c82017-10-17 19:04:42 -0700102static int mpt_set_debug_level(const char *val, const struct kernel_param *kp);
James Bottomleydb47c2d2007-07-28 13:40:21 -0400103module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
104 &mpt_debug_level, 0600);
Joe Perches85ee7a12011-04-23 20:38:19 -0700105MODULE_PARM_DESC(mpt_debug_level,
106 " debug level - refer to mptdebug.h - (default=0)");
Kashyap, Desaie3829682009-01-08 14:27:16 +0530107
Kashyap, Desai2f4c7822009-01-06 15:03:37 +0530108int mpt_fwfault_debug;
109EXPORT_SYMBOL(mpt_fwfault_debug);
Rusty Russell57ba4712010-08-11 23:04:39 -0600110module_param(mpt_fwfault_debug, int, 0600);
Joe Perches85ee7a12011-04-23 20:38:19 -0700111MODULE_PARM_DESC(mpt_fwfault_debug,
112 "Enable detection of Firmware fault and halt Firmware on fault - (default=0)");
Kashyap, Desai2f4c7822009-01-06 15:03:37 +0530113
Ferenc Wagner8af3d8d2011-08-25 14:44:57 +0200114static char MptCallbacksName[MPT_MAX_PROTOCOL_DRIVERS]
115 [MPT_MAX_CALLBACKNAME_LEN+1];
Prakash, Sathya436ace72007-07-24 15:42:08 +0530116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117#ifdef MFCNT
118static int mfcounter = 0;
119#define PRINT_MF_COUNT 20000
120#endif
121
122/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
123/*
124 * Public data...
125 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127#define WHOINIT_UNKNOWN 0xAA
128
129/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
130/*
131 * Private data...
132 */
133 /* Adapter link list */
134LIST_HEAD(ioc_list);
135 /* Callback lookup table */
136static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
137 /* Protocol driver class lookup table */
138static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
139 /* Event handler lookup table */
140static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
141 /* Reset handler lookup table */
142static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
143static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
144
Erik Ekmane47c11c2009-12-14 21:21:56 +0100145#ifdef CONFIG_PROC_FS
146static struct proc_dir_entry *mpt_proc_root_dir;
147#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530149/*
150 * Driver Callback Index's
151 */
152static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
153static u8 last_drv_idx;
154
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
156/*
157 * Forward protos...
158 */
David Howells7d12e782006-10-05 14:55:46 +0100159static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530160static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
161 MPT_FRAME_HDR *reply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
163 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
164 int sleepFlag);
165static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
166static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
167static void mpt_adapter_disable(MPT_ADAPTER *ioc);
168static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
169
170static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
171static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
173static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
174static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
175static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
176static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200177static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
179static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
180static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
181static int PrimeIocFifos(MPT_ADAPTER *ioc);
182static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
183static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
184static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
185static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200187int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
189static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
190static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
191static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530192static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Kashyap, Desaifd761752009-05-29 16:39:06 +0530193static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch,
194 int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200196static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
197static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
199#ifdef CONFIG_PROC_FS
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -0700200static const struct file_operations mpt_summary_proc_fops;
201static const struct file_operations mpt_version_proc_fops;
202static const struct file_operations mpt_iocinfo_proc_fops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203#endif
204static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
205
Kashyap, Desaifd761752009-05-29 16:39:06 +0530206static int ProcessEventNotification(MPT_ADAPTER *ioc,
207 EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700208static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700210static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530211static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info , u8 cb_idx);
Moore, Ericc972c702006-03-14 09:14:06 -0700212static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700213static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214
215/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216static int __init fusion_init (void);
217static void __exit fusion_exit (void);
218
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219#define CHIPREG_READ32(addr) readl_relaxed(addr)
220#define CHIPREG_READ32_dmasync(addr) readl(addr)
221#define CHIPREG_WRITE32(addr,val) writel(val, addr)
222#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
223#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
224
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600225static void
226pci_disable_io_access(struct pci_dev *pdev)
227{
228 u16 command_reg;
229
230 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
231 command_reg &= ~1;
232 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
233}
234
235static void
236pci_enable_io_access(struct pci_dev *pdev)
237{
238 u16 command_reg;
239
240 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
241 command_reg |= 1;
242 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
243}
244
Kees Cook24da2c82017-10-17 19:04:42 -0700245static int mpt_set_debug_level(const char *val, const struct kernel_param *kp)
James Bottomleydb47c2d2007-07-28 13:40:21 -0400246{
247 int ret = param_set_int(val, kp);
248 MPT_ADAPTER *ioc;
249
250 if (ret)
251 return ret;
252
253 list_for_each_entry(ioc, &ioc_list, list)
254 ioc->debug_level = mpt_debug_level;
255 return 0;
256}
257
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530258/**
259 * mpt_get_cb_idx - obtain cb_idx for registered driver
260 * @dclass: class driver enum
261 *
262 * Returns cb_idx, or zero means it wasn't found
263 **/
264static u8
265mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
266{
267 u8 cb_idx;
268
269 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
270 if (MptDriverClass[cb_idx] == dclass)
271 return cb_idx;
272 return 0;
273}
274
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530275/**
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530276 * mpt_is_discovery_complete - determine if discovery has completed
277 * @ioc: per adatper instance
278 *
279 * Returns 1 when discovery completed, else zero.
280 */
281static int
282mpt_is_discovery_complete(MPT_ADAPTER *ioc)
283{
284 ConfigExtendedPageHeader_t hdr;
285 CONFIGPARMS cfg;
286 SasIOUnitPage0_t *buffer;
287 dma_addr_t dma_handle;
288 int rc = 0;
289
290 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
291 memset(&cfg, 0, sizeof(CONFIGPARMS));
292 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
293 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
294 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
295 cfg.cfghdr.ehdr = &hdr;
296 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
297
298 if ((mpt_config(ioc, &cfg)))
299 goto out;
300 if (!hdr.ExtPageLength)
301 goto out;
302
303 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
304 &dma_handle);
305 if (!buffer)
306 goto out;
307
308 cfg.physAddr = dma_handle;
309 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
310
311 if ((mpt_config(ioc, &cfg)))
312 goto out_free_consistent;
313
314 if (!(buffer->PhyData[0].PortFlags &
315 MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS))
316 rc = 1;
317
318 out_free_consistent:
319 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
320 buffer, dma_handle);
321 out:
322 return rc;
323}
324
kashyap.desai@lsi.come62cca12011-08-04 16:42:15 +0530325
326/**
327 * mpt_remove_dead_ioc_func - kthread context to remove dead ioc
328 * @arg: input argument, used to derive ioc
329 *
330 * Return 0 if controller is removed from pci subsystem.
331 * Return -1 for other case.
332 */
333static int mpt_remove_dead_ioc_func(void *arg)
334{
335 MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
336 struct pci_dev *pdev;
337
338 if ((ioc == NULL))
339 return -1;
340
341 pdev = ioc->pcidev;
342 if ((pdev == NULL))
343 return -1;
344
Rafael J. Wysocki64cdb412014-01-10 15:27:56 +0100345 pci_stop_and_remove_bus_device_locked(pdev);
kashyap.desai@lsi.come62cca12011-08-04 16:42:15 +0530346 return 0;
347}
348
349
350
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530351/**
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530352 * mpt_fault_reset_work - work performed on workq after ioc fault
353 * @work: input argument, used to derive ioc
354 *
355**/
356static void
357mpt_fault_reset_work(struct work_struct *work)
358{
359 MPT_ADAPTER *ioc =
360 container_of(work, MPT_ADAPTER, fault_reset_work.work);
361 u32 ioc_raw_state;
362 int rc;
363 unsigned long flags;
kashyap.desai@lsi.come62cca12011-08-04 16:42:15 +0530364 MPT_SCSI_HOST *hd;
365 struct task_struct *p;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530366
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530367 if (ioc->ioc_reset_in_progress || !ioc->active)
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530368 goto out;
369
kashyap.desai@lsi.come62cca12011-08-04 16:42:15 +0530370
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530371 ioc_raw_state = mpt_GetIocState(ioc, 0);
kashyap.desai@lsi.come62cca12011-08-04 16:42:15 +0530372 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_MASK) {
373 printk(MYIOC_s_INFO_FMT "%s: IOC is non-operational !!!!\n",
374 ioc->name, __func__);
375
376 /*
377 * Call mptscsih_flush_pending_cmds callback so that we
378 * flush all pending commands back to OS.
379 * This call is required to aovid deadlock at block layer.
380 * Dead IOC will fail to do diag reset,and this call is safe
381 * since dead ioc will never return any command back from HW.
382 */
383 hd = shost_priv(ioc->sh);
384 ioc->schedule_dead_ioc_flush_running_cmds(hd);
385
386 /*Remove the Dead Host */
387 p = kthread_run(mpt_remove_dead_ioc_func, ioc,
388 "mpt_dead_ioc_%d", ioc->id);
389 if (IS_ERR(p)) {
390 printk(MYIOC_s_ERR_FMT
391 "%s: Running mpt_dead_ioc thread failed !\n",
392 ioc->name, __func__);
393 } else {
394 printk(MYIOC_s_WARN_FMT
395 "%s: Running mpt_dead_ioc thread success !\n",
396 ioc->name, __func__);
397 }
398 return; /* don't rearm timer */
399 }
400
401 if ((ioc_raw_state & MPI_IOC_STATE_MASK)
402 == MPI_IOC_STATE_FAULT) {
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530403 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700404 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530405 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700406 ioc->name, __func__);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530407 rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
408 printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700409 __func__, (rc == 0) ? "success" : "failed");
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530410 ioc_raw_state = mpt_GetIocState(ioc, 0);
411 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
412 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
413 "reset (%04xh)\n", ioc->name, ioc_raw_state &
414 MPI_DOORBELL_DATA_MASK);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530415 } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) {
416 if ((mpt_is_discovery_complete(ioc))) {
417 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing "
418 "discovery_quiesce_io flag\n", ioc->name));
419 ioc->sas_discovery_quiesce_io = 0;
420 }
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530421 }
422
423 out:
424 /*
425 * Take turns polling alternate controller
426 */
427 if (ioc->alt_ioc)
428 ioc = ioc->alt_ioc;
429
430 /* rearm the timer */
Kashyap, Desai2f187862009-05-29 16:52:37 +0530431 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530432 if (ioc->reset_work_q)
433 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
434 msecs_to_jiffies(MPT_POLLING_INTERVAL));
Kashyap, Desai2f187862009-05-29 16:52:37 +0530435 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530436}
437
438
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600439/*
440 * Process turbo (context) reply...
441 */
442static void
443mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
444{
445 MPT_FRAME_HDR *mf = NULL;
446 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530447 u16 req_idx = 0;
448 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600449
Prakash, Sathya436ace72007-07-24 15:42:08 +0530450 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600451 ioc->name, pa));
452
453 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
454 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
455 req_idx = pa & 0x0000FFFF;
456 cb_idx = (pa & 0x00FF0000) >> 16;
457 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
458 break;
459 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530460 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600461 /*
462 * Blind set of mf to NULL here was fatal
463 * after lan_reply says "freeme"
464 * Fix sort of combined with an optimization here;
465 * added explicit check for case where lan_reply
466 * was just returning 1 and doing nothing else.
467 * For this case skip the callback, but set up
468 * proper mf value first here:-)
469 */
470 if ((pa & 0x58000000) == 0x58000000) {
471 req_idx = pa & 0x0000FFFF;
472 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
473 mpt_free_msg_frame(ioc, mf);
474 mb();
475 return;
476 break;
477 }
478 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
479 break;
480 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530481 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600482 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
483 break;
484 default:
485 cb_idx = 0;
486 BUG();
487 }
488
489 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530490 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600491 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600492 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700493 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600494 goto out;
495 }
496
497 if (MptCallbacks[cb_idx](ioc, mf, mr))
498 mpt_free_msg_frame(ioc, mf);
499 out:
500 mb();
501}
502
503static void
504mpt_reply(MPT_ADAPTER *ioc, u32 pa)
505{
506 MPT_FRAME_HDR *mf;
507 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530508 u16 req_idx;
509 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600510 int freeme;
511
512 u32 reply_dma_low;
513 u16 ioc_stat;
514
515 /* non-TURBO reply! Hmmm, something may be up...
516 * Newest turbo reply mechanism; get address
517 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
518 */
519
520 /* Map DMA address of reply header to cpu address.
521 * pa is 32 bits - but the dma address may be 32 or 64 bits
522 * get offset based only only the low addresses
523 */
524
525 reply_dma_low = (pa <<= 1);
526 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
527 (reply_dma_low - ioc->reply_frames_low_dma));
528
529 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
530 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
531 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
532
Prakash, Sathya436ace72007-07-24 15:42:08 +0530533 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 -0600534 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600535 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600536
537 /* Check/log IOC log info
538 */
539 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
540 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
541 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
542 if (ioc->bus_type == FC)
543 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700544 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700545 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600546 else if (ioc->bus_type == SAS)
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530547 mpt_sas_log_info(ioc, log_info, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600548 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600549
Eric Moorec6c727a2007-01-29 09:44:54 -0700550 if (ioc_stat & MPI_IOCSTATUS_MASK)
551 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600552
553 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530554 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600555 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600556 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700557 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600558 freeme = 0;
559 goto out;
560 }
561
562 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
563
564 out:
565 /* Flush (non-TURBO) reply with a WRITE! */
566 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
567
568 if (freeme)
569 mpt_free_msg_frame(ioc, mf);
570 mb();
571}
572
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800574/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
576 * @irq: irq number (not used)
577 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 *
579 * This routine is registered via the request_irq() kernel API call,
580 * and handles all interrupts generated from a specific MPT adapter
581 * (also referred to as a IO Controller or IOC).
582 * This routine must clear the interrupt from the adapter and does
583 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200584 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 *
586 * This routine handles register-level access of the adapter but
587 * dispatches (calls) a protocol-specific callback routine to handle
588 * the protocol-specific details of the MPT request completion.
589 */
590static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100591mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600593 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600594 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
595
596 if (pa == 0xFFFFFFFF)
597 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
599 /*
600 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600602 do {
603 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600604 mpt_reply(ioc, pa);
605 else
606 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600607 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
608 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
610 return IRQ_HANDLED;
611}
612
613/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800614/**
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530615 * mptbase_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 * @ioc: Pointer to MPT_ADAPTER structure
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530617 * @req: Pointer to original MPT request frame
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
619 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800620 * MPT base driver's callback routine; all base driver
621 * "internal" request/reply processing is routed here.
622 * Currently used for EventNotification and EventAck handling.
623 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200624 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 * should be freed, or 0 if it shouldn't.
626 */
627static int
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530628mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530630 EventNotificationReply_t *pEventReply;
631 u8 event;
632 int evHandlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 int freereq = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530635 switch (reply->u.hdr.Function) {
636 case MPI_FUNCTION_EVENT_NOTIFICATION:
637 pEventReply = (EventNotificationReply_t *)reply;
638 evHandlers = 0;
639 ProcessEventNotification(ioc, pEventReply, &evHandlers);
640 event = le32_to_cpu(pEventReply->Event) & 0xFF;
641 if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 freereq = 0;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530643 if (event != MPI_EVENT_EVENT_CHANGE)
644 break;
645 case MPI_FUNCTION_CONFIG:
646 case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
647 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Joe Lawrence9f213162014-06-25 17:06:54 -0400648 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
649 memcpy(ioc->mptbase_cmds.reply, reply,
650 min(MPT_DEFAULT_FRAME_SIZE,
651 4 * reply->u.reply.MsgLength));
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530652 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
653 ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
654 complete(&ioc->mptbase_cmds.done);
655 } else
656 freereq = 0;
657 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF)
658 freereq = 1;
659 break;
660 case MPI_FUNCTION_EVENT_ACK:
661 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
662 "EventAck reply received\n", ioc->name));
663 break;
664 default:
665 printk(MYIOC_s_ERR_FMT
666 "Unexpected msg function (=%02Xh) reply received!\n",
667 ioc->name, reply->u.hdr.Function);
668 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 }
670
671 /*
672 * Conditionally tell caller to free the original
673 * EventNotification/EventAck/unexpected request frame!
674 */
675 return freereq;
676}
677
678/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
679/**
680 * mpt_register - Register protocol-specific main callback handler.
681 * @cbfunc: callback function pointer
682 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
Randy Dunlapfc58fb12010-08-14 13:05:57 -0700683 * @func_name: call function's name
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 *
685 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800686 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 * protocol-specific driver must do this before it will be able to
688 * use any IOC resources, such as obtaining request frames.
689 *
690 * NOTES: The SCSI protocol driver currently calls this routine thrice
691 * in order to register separate callbacks; one for "normal" SCSI IO;
692 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
693 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530694 * Returns u8 valued "handle" in the range (and S.O.D. order)
695 * {N,...,7,6,5,...,1} if successful.
696 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
697 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530699u8
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530700mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass, char *func_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530702 u8 cb_idx;
703 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
705 /*
706 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
707 * (slot/handle 0 is reserved!)
708 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530709 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
710 if (MptCallbacks[cb_idx] == NULL) {
711 MptCallbacks[cb_idx] = cbfunc;
712 MptDriverClass[cb_idx] = dclass;
713 MptEvHandlers[cb_idx] = NULL;
714 last_drv_idx = cb_idx;
Ferenc Wagner8af3d8d2011-08-25 14:44:57 +0200715 strlcpy(MptCallbacksName[cb_idx], func_name,
716 MPT_MAX_CALLBACKNAME_LEN+1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 break;
718 }
719 }
720
721 return last_drv_idx;
722}
723
724/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
725/**
726 * mpt_deregister - Deregister a protocol drivers resources.
727 * @cb_idx: previously registered callback handle
728 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800729 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 * module is unloaded.
731 */
732void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530733mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600735 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 MptCallbacks[cb_idx] = NULL;
737 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
738 MptEvHandlers[cb_idx] = NULL;
739
740 last_drv_idx++;
741 }
742}
743
744/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
745/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800746 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 * @cb_idx: previously registered (via mpt_register) callback handle
748 * @ev_cbfunc: callback function
749 *
750 * This routine can be called by one or more protocol-specific drivers
751 * if/when they choose to be notified of MPT events.
752 *
753 * Returns 0 for success.
754 */
755int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530756mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600758 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 return -1;
760
761 MptEvHandlers[cb_idx] = ev_cbfunc;
762 return 0;
763}
764
765/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
766/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800767 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 * @cb_idx: previously registered callback handle
769 *
770 * Each protocol-specific driver should call this routine
771 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800772 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 */
774void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530775mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600777 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 return;
779
780 MptEvHandlers[cb_idx] = NULL;
781}
782
783/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
784/**
785 * mpt_reset_register - Register protocol-specific IOC reset handler.
786 * @cb_idx: previously registered (via mpt_register) callback handle
787 * @reset_func: reset function
788 *
789 * This routine can be called by one or more protocol-specific drivers
790 * if/when they choose to be notified of IOC resets.
791 *
792 * Returns 0 for success.
793 */
794int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530795mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530797 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 return -1;
799
800 MptResetHandlers[cb_idx] = reset_func;
801 return 0;
802}
803
804/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
805/**
806 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
807 * @cb_idx: previously registered callback handle
808 *
809 * Each protocol-specific driver should call this routine
810 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800811 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 */
813void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530814mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530816 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 return;
818
819 MptResetHandlers[cb_idx] = NULL;
820}
821
822/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
823/**
824 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800825 * @dd_cbfunc: driver callbacks struct
826 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 */
828int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530829mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830{
831 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600832 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
Eric Moore8d6d83e2007-09-14 18:47:40 -0600834 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400835 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
837 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
838
839 /* call per pci device probe entry point */
840 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600841 id = ioc->pcidev->driver ?
842 ioc->pcidev->driver->id_table : NULL;
843 if (dd_cbfunc->probe)
844 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 }
846
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400847 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848}
849
850/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
851/**
852 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800853 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 */
855void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530856mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857{
858 struct mpt_pci_driver *dd_cbfunc;
859 MPT_ADAPTER *ioc;
860
Eric Moore8d6d83e2007-09-14 18:47:40 -0600861 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 return;
863
864 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
865
866 list_for_each_entry(ioc, &ioc_list, list) {
867 if (dd_cbfunc->remove)
868 dd_cbfunc->remove(ioc->pcidev);
869 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200870
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 MptDeviceDriverHandlers[cb_idx] = NULL;
872}
873
874
875/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
876/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800877 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530878 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 * @ioc: Pointer to MPT adapter structure
880 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800881 * Obtain an MPT request frame from the pool (of 1024) that are
882 * allocated per MPT adapter.
883 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 * Returns pointer to a MPT request frame or %NULL if none are available
885 * or IOC is not active.
886 */
887MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530888mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889{
890 MPT_FRAME_HDR *mf;
891 unsigned long flags;
892 u16 req_idx; /* Request index */
893
894 /* validate handle and ioc identifier */
895
896#ifdef MFCNT
897 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600898 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
899 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900#endif
901
902 /* If interrupts are not attached, do not return a request frame */
903 if (!ioc->active)
904 return NULL;
905
906 spin_lock_irqsave(&ioc->FreeQlock, flags);
907 if (!list_empty(&ioc->FreeQ)) {
908 int req_offset;
909
910 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
911 u.frame.linkage.list);
912 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200913 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530914 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
916 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500917 req_idx = req_offset / ioc->req_sz;
918 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600920 /* Default, will be changed if necessary in SG generation */
921 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922#ifdef MFCNT
923 ioc->mfcnt++;
924#endif
925 }
926 else
927 mf = NULL;
928 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
929
930#ifdef MFCNT
931 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600932 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
933 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
934 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 mfcounter++;
936 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600937 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
938 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939#endif
940
Eric Moore29dd3602007-09-14 18:46:51 -0600941 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
942 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 return mf;
944}
945
946/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
947/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800948 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530949 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 * @ioc: Pointer to MPT adapter structure
951 * @mf: Pointer to MPT request frame
952 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800953 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 * specific MPT adapter.
955 */
956void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530957mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958{
959 u32 mf_dma_addr;
960 int req_offset;
961 u16 req_idx; /* Request index */
962
963 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530964 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
966 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500967 req_idx = req_offset / ioc->req_sz;
968 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
970
Prakash, Sathya436ace72007-07-24 15:42:08 +0530971 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200973 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600974 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
975 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
976 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
978}
979
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530980/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800981 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530982 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530983 * @ioc: Pointer to MPT adapter structure
984 * @mf: Pointer to MPT request frame
985 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800986 * Send a protocol-specific MPT request frame to an IOC using
987 * hi-priority request queue.
988 *
989 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530990 * specific MPT adapter.
991 **/
992void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530993mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530994{
995 u32 mf_dma_addr;
996 int req_offset;
997 u16 req_idx; /* Request index */
998
999 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301000 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301001 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
1002 req_idx = req_offset / ioc->req_sz;
1003 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
1004 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
1005
1006 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
1007
1008 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
1009 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
1010 ioc->name, mf_dma_addr, req_idx));
1011 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
1012}
1013
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1015/**
1016 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 * @ioc: Pointer to MPT adapter structure
1018 * @mf: Pointer to MPT request frame
1019 *
1020 * This routine places a MPT request frame back on the MPT adapter's
1021 * FreeQ.
1022 */
1023void
1024mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
1025{
1026 unsigned long flags;
1027
1028 /* Put Request back on FreeQ! */
1029 spin_lock_irqsave(&ioc->FreeQlock, flags);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301030 if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf)
1031 goto out;
1032 /* signature to know if this mf is freed */
1033 mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf);
Matthew Wilcoxecc3bc92014-03-27 16:40:35 -04001034 list_add(&mf->u.frame.linkage.list, &ioc->FreeQ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035#ifdef MFCNT
1036 ioc->mfcnt--;
1037#endif
Kashyap, Desai2f187862009-05-29 16:52:37 +05301038 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1040}
1041
1042/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1043/**
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301044 * mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 * @pAddr: virtual address for SGE
1046 * @flagslength: SGE flags and data transfer length
1047 * @dma_addr: Physical address
1048 *
1049 * This routine places a MPT request frame back on the MPT adapter's
1050 * FreeQ.
1051 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301052static void
1053mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054{
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301055 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
1056 pSge->FlagsLength = cpu_to_le32(flagslength);
1057 pSge->Address = cpu_to_le32(dma_addr);
1058}
1059
1060/**
1061 * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
1062 * @pAddr: virtual address for SGE
1063 * @flagslength: SGE flags and data transfer length
1064 * @dma_addr: Physical address
1065 *
1066 * This routine places a MPT request frame back on the MPT adapter's
1067 * FreeQ.
1068 **/
1069static void
1070mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1071{
1072 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1073 pSge->Address.Low = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301074 (lower_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301075 pSge->Address.High = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301076 (upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301077 pSge->FlagsLength = cpu_to_le32
1078 ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1079}
1080
1081/**
Randy Dunlap9cf46a32009-06-13 19:37:18 -07001082 * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr (1078 workaround).
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301083 * @pAddr: virtual address for SGE
1084 * @flagslength: SGE flags and data transfer length
1085 * @dma_addr: Physical address
1086 *
1087 * This routine places a MPT request frame back on the MPT adapter's
1088 * FreeQ.
1089 **/
1090static void
1091mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1092{
1093 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1094 u32 tmp;
1095
1096 pSge->Address.Low = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301097 (lower_32_bits(dma_addr));
1098 tmp = (u32)(upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301099
1100 /*
1101 * 1078 errata workaround for the 36GB limitation
1102 */
1103 if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {
1104 flagslength |=
1105 MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
1106 tmp |= (1<<31);
1107 if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
1108 printk(KERN_DEBUG "1078 P0M2 addressing for "
1109 "addr = 0x%llx len = %d\n",
1110 (unsigned long long)dma_addr,
1111 MPI_SGE_LENGTH(flagslength));
1112 }
1113
1114 pSge->Address.High = cpu_to_le32(tmp);
1115 pSge->FlagsLength = cpu_to_le32(
1116 (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1117}
1118
1119/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1120/**
1121 * mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
1122 * @pAddr: virtual address for SGE
1123 * @next: nextChainOffset value (u32's)
1124 * @length: length of next SGL segment
1125 * @dma_addr: Physical address
1126 *
1127 */
1128static void
1129mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1130{
1131 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
1132 pChain->Length = cpu_to_le16(length);
1133 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
1134 pChain->NextChainOffset = next;
1135 pChain->Address = cpu_to_le32(dma_addr);
1136}
1137
1138/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1139/**
1140 * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
1141 * @pAddr: virtual address for SGE
1142 * @next: nextChainOffset value (u32's)
1143 * @length: length of next SGL segment
1144 * @dma_addr: Physical address
1145 *
1146 */
1147static void
1148mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1149{
1150 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 u32 tmp = dma_addr & 0xFFFFFFFF;
1152
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301153 pChain->Length = cpu_to_le16(length);
1154 pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
1155 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301157 pChain->NextChainOffset = next;
1158
1159 pChain->Address.Low = cpu_to_le32(tmp);
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301160 tmp = (u32)(upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301161 pChain->Address.High = cpu_to_le32(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162}
1163
1164/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1165/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001166 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301167 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 * @ioc: Pointer to MPT adapter structure
1169 * @reqBytes: Size of the request in bytes
1170 * @req: Pointer to MPT request frame
1171 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1172 *
1173 * This routine is used exclusively to send MptScsiTaskMgmt
1174 * requests since they are required to be sent via doorbell handshake.
1175 *
1176 * NOTE: It is the callers responsibility to byte-swap fields in the
1177 * request which are greater than 1 byte in size.
1178 *
1179 * Returns 0 for success, non-zero for failure.
1180 */
1181int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301182mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183{
Eric Moorecd2c6192007-01-29 09:47:47 -07001184 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 u8 *req_as_bytes;
1186 int ii;
1187
1188 /* State is known to be good upon entering
1189 * this function so issue the bus reset
1190 * request.
1191 */
1192
1193 /*
1194 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1195 * setting cb_idx/req_idx. But ONLY if this request
1196 * is in proper (pre-alloc'd) request buffer range...
1197 */
1198 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1199 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1200 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1201 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301202 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 }
1204
1205 /* Make sure there are no doorbells */
1206 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001207
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1209 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1210 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1211
1212 /* Wait for IOC doorbell int */
1213 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1214 return ii;
1215 }
1216
1217 /* Read doorbell and check for active bit */
1218 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1219 return -5;
1220
Eric Moore29dd3602007-09-14 18:46:51 -06001221 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001222 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223
1224 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1225
1226 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1227 return -2;
1228 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001229
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 /* Send request via doorbell handshake */
1231 req_as_bytes = (u8 *) req;
1232 for (ii = 0; ii < reqBytes/4; ii++) {
1233 u32 word;
1234
1235 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1236 (req_as_bytes[(ii*4) + 1] << 8) |
1237 (req_as_bytes[(ii*4) + 2] << 16) |
1238 (req_as_bytes[(ii*4) + 3] << 24));
1239 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1240 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1241 r = -3;
1242 break;
1243 }
1244 }
1245
1246 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1247 r = 0;
1248 else
1249 r = -4;
1250
1251 /* Make sure there are no doorbells */
1252 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001253
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 return r;
1255}
1256
1257/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1258/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001259 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001260 * @ioc: Pointer to MPT adapter structure
1261 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001262 * @sleepFlag: Specifies whether the process can sleep
1263 *
1264 * Provides mechanism for the host driver to control the IOC's
1265 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001266 *
1267 * Access Control Value - bits[15:12]
1268 * 0h Reserved
1269 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1270 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1271 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1272 *
1273 * Returns 0 for success, non-zero for failure.
1274 */
1275
1276static int
1277mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1278{
1279 int r = 0;
1280
1281 /* return if in use */
1282 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1283 & MPI_DOORBELL_ACTIVE)
1284 return -1;
1285
1286 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1287
1288 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1289 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1290 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1291 (access_control_value<<12)));
1292
1293 /* Wait for IOC to clear Doorbell Status bit */
1294 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1295 return -2;
1296 }else
1297 return 0;
1298}
1299
1300/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1301/**
1302 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001303 * @ioc: Pointer to pointer to IOC adapter
1304 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001305 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001306 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001307 * Returns 0 for success, non-zero for failure.
1308 */
1309static int
1310mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1311{
1312 char *psge;
1313 int flags_length;
1314 u32 host_page_buffer_sz=0;
1315
1316 if(!ioc->HostPageBuffer) {
1317
1318 host_page_buffer_sz =
1319 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1320
1321 if(!host_page_buffer_sz)
1322 return 0; /* fw doesn't need any host buffers */
1323
1324 /* spin till we get enough memory */
1325 while(host_page_buffer_sz > 0) {
1326
1327 if((ioc->HostPageBuffer = pci_alloc_consistent(
1328 ioc->pcidev,
1329 host_page_buffer_sz,
1330 &ioc->HostPageBuffer_dma)) != NULL) {
1331
Prakash, Sathya436ace72007-07-24 15:42:08 +05301332 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001333 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001334 ioc->name, ioc->HostPageBuffer,
1335 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001336 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001337 ioc->alloc_total += host_page_buffer_sz;
1338 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1339 break;
1340 }
1341
1342 host_page_buffer_sz -= (4*1024);
1343 }
1344 }
1345
1346 if(!ioc->HostPageBuffer) {
1347 printk(MYIOC_s_ERR_FMT
1348 "Failed to alloc memory for host_page_buffer!\n",
1349 ioc->name);
1350 return -999;
1351 }
1352
1353 psge = (char *)&ioc_init->HostPageBufferSGE;
1354 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1355 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001356 MPI_SGE_FLAGS_HOST_TO_IOC |
1357 MPI_SGE_FLAGS_END_OF_BUFFER;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001358 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1359 flags_length |= ioc->HostPageBuffer_sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301360 ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001361 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1362
1363return 0;
1364}
1365
1366/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1367/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001368 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 * @iocid: IOC unique identifier (integer)
1370 * @iocpp: Pointer to pointer to IOC adapter
1371 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001372 * Given a unique IOC identifier, set pointer to the associated MPT
1373 * adapter structure.
1374 *
1375 * Returns iocid and sets iocpp if iocid is found.
1376 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 */
1378int
1379mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1380{
1381 MPT_ADAPTER *ioc;
1382
1383 list_for_each_entry(ioc,&ioc_list,list) {
1384 if (ioc->id == iocid) {
1385 *iocpp =ioc;
1386 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001389
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 *iocpp = NULL;
1391 return -1;
1392}
1393
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301394/**
1395 * mpt_get_product_name - returns product string
1396 * @vendor: pci vendor id
1397 * @device: pci device id
1398 * @revision: pci revision id
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301399 *
1400 * Returns product string displayed when driver loads,
1401 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1402 *
1403 **/
Joe Lawrencec9834c72014-06-25 17:06:28 -04001404static const char*
1405mpt_get_product_name(u16 vendor, u16 device, u8 revision)
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301406{
1407 char *product_str = NULL;
1408
1409 if (vendor == PCI_VENDOR_ID_BROCADE) {
1410 switch (device)
1411 {
1412 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1413 switch (revision)
1414 {
1415 case 0x00:
1416 product_str = "BRE040 A0";
1417 break;
1418 case 0x01:
1419 product_str = "BRE040 A1";
1420 break;
1421 default:
1422 product_str = "BRE040";
1423 break;
1424 }
1425 break;
1426 }
1427 goto out;
1428 }
1429
1430 switch (device)
1431 {
1432 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1433 product_str = "LSIFC909 B1";
1434 break;
1435 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1436 product_str = "LSIFC919 B0";
1437 break;
1438 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1439 product_str = "LSIFC929 B0";
1440 break;
1441 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1442 if (revision < 0x80)
1443 product_str = "LSIFC919X A0";
1444 else
1445 product_str = "LSIFC919XL A1";
1446 break;
1447 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1448 if (revision < 0x80)
1449 product_str = "LSIFC929X A0";
1450 else
1451 product_str = "LSIFC929XL A1";
1452 break;
1453 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1454 product_str = "LSIFC939X A1";
1455 break;
1456 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1457 product_str = "LSIFC949X A1";
1458 break;
1459 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1460 switch (revision)
1461 {
1462 case 0x00:
1463 product_str = "LSIFC949E A0";
1464 break;
1465 case 0x01:
1466 product_str = "LSIFC949E A1";
1467 break;
1468 default:
1469 product_str = "LSIFC949E";
1470 break;
1471 }
1472 break;
1473 case MPI_MANUFACTPAGE_DEVID_53C1030:
1474 switch (revision)
1475 {
1476 case 0x00:
1477 product_str = "LSI53C1030 A0";
1478 break;
1479 case 0x01:
1480 product_str = "LSI53C1030 B0";
1481 break;
1482 case 0x03:
1483 product_str = "LSI53C1030 B1";
1484 break;
1485 case 0x07:
1486 product_str = "LSI53C1030 B2";
1487 break;
1488 case 0x08:
1489 product_str = "LSI53C1030 C0";
1490 break;
1491 case 0x80:
1492 product_str = "LSI53C1030T A0";
1493 break;
1494 case 0x83:
1495 product_str = "LSI53C1030T A2";
1496 break;
1497 case 0x87:
1498 product_str = "LSI53C1030T A3";
1499 break;
1500 case 0xc1:
1501 product_str = "LSI53C1020A A1";
1502 break;
1503 default:
1504 product_str = "LSI53C1030";
1505 break;
1506 }
1507 break;
1508 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1509 switch (revision)
1510 {
1511 case 0x03:
1512 product_str = "LSI53C1035 A2";
1513 break;
1514 case 0x04:
1515 product_str = "LSI53C1035 B0";
1516 break;
1517 default:
1518 product_str = "LSI53C1035";
1519 break;
1520 }
1521 break;
1522 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1523 switch (revision)
1524 {
1525 case 0x00:
1526 product_str = "LSISAS1064 A1";
1527 break;
1528 case 0x01:
1529 product_str = "LSISAS1064 A2";
1530 break;
1531 case 0x02:
1532 product_str = "LSISAS1064 A3";
1533 break;
1534 case 0x03:
1535 product_str = "LSISAS1064 A4";
1536 break;
1537 default:
1538 product_str = "LSISAS1064";
1539 break;
1540 }
1541 break;
1542 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1543 switch (revision)
1544 {
1545 case 0x00:
1546 product_str = "LSISAS1064E A0";
1547 break;
1548 case 0x01:
1549 product_str = "LSISAS1064E B0";
1550 break;
1551 case 0x02:
1552 product_str = "LSISAS1064E B1";
1553 break;
1554 case 0x04:
1555 product_str = "LSISAS1064E B2";
1556 break;
1557 case 0x08:
1558 product_str = "LSISAS1064E B3";
1559 break;
1560 default:
1561 product_str = "LSISAS1064E";
1562 break;
1563 }
1564 break;
1565 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1566 switch (revision)
1567 {
1568 case 0x00:
1569 product_str = "LSISAS1068 A0";
1570 break;
1571 case 0x01:
1572 product_str = "LSISAS1068 B0";
1573 break;
1574 case 0x02:
1575 product_str = "LSISAS1068 B1";
1576 break;
1577 default:
1578 product_str = "LSISAS1068";
1579 break;
1580 }
1581 break;
1582 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1583 switch (revision)
1584 {
1585 case 0x00:
1586 product_str = "LSISAS1068E A0";
1587 break;
1588 case 0x01:
1589 product_str = "LSISAS1068E B0";
1590 break;
1591 case 0x02:
1592 product_str = "LSISAS1068E B1";
1593 break;
1594 case 0x04:
1595 product_str = "LSISAS1068E B2";
1596 break;
1597 case 0x08:
1598 product_str = "LSISAS1068E B3";
1599 break;
1600 default:
1601 product_str = "LSISAS1068E";
1602 break;
1603 }
1604 break;
1605 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1606 switch (revision)
1607 {
1608 case 0x00:
1609 product_str = "LSISAS1078 A0";
1610 break;
1611 case 0x01:
1612 product_str = "LSISAS1078 B0";
1613 break;
1614 case 0x02:
1615 product_str = "LSISAS1078 C0";
1616 break;
1617 case 0x03:
1618 product_str = "LSISAS1078 C1";
1619 break;
1620 case 0x04:
1621 product_str = "LSISAS1078 C2";
1622 break;
1623 default:
1624 product_str = "LSISAS1078";
1625 break;
1626 }
1627 break;
1628 }
1629
1630 out:
Joe Lawrencec9834c72014-06-25 17:06:28 -04001631 return product_str;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301632}
1633
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301634/**
1635 * mpt_mapresources - map in memory mapped io
1636 * @ioc: Pointer to pointer to IOC adapter
1637 *
1638 **/
1639static int
1640mpt_mapresources(MPT_ADAPTER *ioc)
1641{
1642 u8 __iomem *mem;
1643 int ii;
Pravin Bathijae46b63b2009-12-02 17:51:46 -08001644 resource_size_t mem_phys;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301645 unsigned long port;
1646 u32 msize;
1647 u32 psize;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301648 int r = -ENODEV;
1649 struct pci_dev *pdev;
1650
1651 pdev = ioc->pcidev;
1652 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1653 if (pci_enable_device_mem(pdev)) {
1654 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1655 "failed\n", ioc->name);
1656 return r;
1657 }
1658 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1659 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1660 "MEM failed\n", ioc->name);
Hanjun Guo20953a62012-08-11 10:58:36 +08001661 goto out_pci_disable_device;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301662 }
1663
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301664 if (sizeof(dma_addr_t) > 4) {
1665 const uint64_t required_mask = dma_get_required_mask
1666 (&pdev->dev);
1667 if (required_mask > DMA_BIT_MASK(32)
1668 && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
1669 && !pci_set_consistent_dma_mask(pdev,
1670 DMA_BIT_MASK(64))) {
1671 ioc->dma_mask = DMA_BIT_MASK(64);
1672 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1673 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1674 ioc->name));
1675 } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1676 && !pci_set_consistent_dma_mask(pdev,
1677 DMA_BIT_MASK(32))) {
1678 ioc->dma_mask = DMA_BIT_MASK(32);
1679 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1680 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1681 ioc->name));
1682 } else {
1683 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1684 ioc->name, pci_name(pdev));
Hanjun Guo20953a62012-08-11 10:58:36 +08001685 goto out_pci_release_region;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301686 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301687 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301688 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1689 && !pci_set_consistent_dma_mask(pdev,
1690 DMA_BIT_MASK(32))) {
1691 ioc->dma_mask = DMA_BIT_MASK(32);
1692 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1693 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1694 ioc->name));
1695 } else {
1696 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1697 ioc->name, pci_name(pdev));
Hanjun Guo20953a62012-08-11 10:58:36 +08001698 goto out_pci_release_region;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301699 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301700 }
1701
1702 mem_phys = msize = 0;
1703 port = psize = 0;
1704 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1705 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1706 if (psize)
1707 continue;
1708 /* Get I/O space! */
1709 port = pci_resource_start(pdev, ii);
1710 psize = pci_resource_len(pdev, ii);
1711 } else {
1712 if (msize)
1713 continue;
1714 /* Get memmap */
1715 mem_phys = pci_resource_start(pdev, ii);
1716 msize = pci_resource_len(pdev, ii);
1717 }
1718 }
1719 ioc->mem_size = msize;
1720
1721 mem = NULL;
1722 /* Get logical ptr for PciMem0 space */
1723 /*mem = ioremap(mem_phys, msize);*/
1724 mem = ioremap(mem_phys, msize);
1725 if (mem == NULL) {
1726 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1727 " memory!\n", ioc->name);
Hanjun Guo20953a62012-08-11 10:58:36 +08001728 r = -EINVAL;
1729 goto out_pci_release_region;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301730 }
1731 ioc->memmap = mem;
Pravin Bathijae46b63b2009-12-02 17:51:46 -08001732 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %llx\n",
1733 ioc->name, mem, (unsigned long long)mem_phys));
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301734
1735 ioc->mem_phys = mem_phys;
1736 ioc->chip = (SYSIF_REGS __iomem *)mem;
1737
1738 /* Save Port IO values in case we need to do downloadboot */
1739 ioc->pio_mem_phys = port;
1740 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1741
1742 return 0;
Hanjun Guo20953a62012-08-11 10:58:36 +08001743
1744out_pci_release_region:
1745 pci_release_selected_regions(pdev, ioc->bars);
1746out_pci_disable_device:
1747 pci_disable_device(pdev);
1748 return r;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301749}
1750
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001752/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001753 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001755 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 *
1757 * This routine performs all the steps necessary to bring the IOC of
1758 * a MPT adapter to a OPERATIONAL state. This includes registering
1759 * memory regions, registering the interrupt, and allocating request
1760 * and reply memory pools.
1761 *
1762 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1763 * MPT adapter.
1764 *
1765 * Returns 0 for success, non-zero for failure.
1766 *
1767 * TODO: Add support for polled controllers
1768 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001769int
1770mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771{
1772 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301773 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 u8 pcixcmd;
1776 static int mpt_ids = 0;
1777#ifdef CONFIG_PROC_FS
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07001778 struct proc_dir_entry *dent;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779#endif
1780
Jesper Juhl56876192007-08-10 14:50:51 -07001781 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1782 if (ioc == NULL) {
1783 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1784 return -ENOMEM;
1785 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301786
Eric Moore29dd3602007-09-14 18:46:51 -06001787 ioc->id = mpt_ids++;
1788 sprintf(ioc->name, "ioc%d", ioc->id);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301789 dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Jesper Juhl56876192007-08-10 14:50:51 -07001790
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301791 /*
1792 * set initial debug level
1793 * (refer to mptdebug.h)
1794 *
1795 */
1796 ioc->debug_level = mpt_debug_level;
1797 if (mpt_debug_level)
1798 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301799
Eric Moore29dd3602007-09-14 18:46:51 -06001800 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001801
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301802 ioc->pcidev = pdev;
1803 if (mpt_mapresources(ioc)) {
Ewan D. Milnee8c61ec2016-02-23 09:00:12 -05001804 goto out_free_ioc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 }
1806
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301807 /*
1808 * Setting up proper handlers for scatter gather handling
1809 */
1810 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
1811 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
1812 ioc->add_sge = &mpt_add_sge_64bit_1078;
1813 else
1814 ioc->add_sge = &mpt_add_sge_64bit;
1815 ioc->add_chain = &mpt_add_chain_64bit;
1816 ioc->sg_addr_size = 8;
1817 } else {
1818 ioc->add_sge = &mpt_add_sge;
1819 ioc->add_chain = &mpt_add_chain;
1820 ioc->sg_addr_size = 4;
1821 }
1822 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
1823
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 ioc->alloc_total = sizeof(MPT_ADAPTER);
1825 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1826 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001827
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301829 spin_lock_init(&ioc->taskmgmt_lock);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05301830 mutex_init(&ioc->internal_cmds.mutex);
1831 init_completion(&ioc->internal_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301832 mutex_init(&ioc->mptbase_cmds.mutex);
1833 init_completion(&ioc->mptbase_cmds.done);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301834 mutex_init(&ioc->taskmgmt_cmds.mutex);
1835 init_completion(&ioc->taskmgmt_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301836
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 /* Initialize the event logging.
1838 */
1839 ioc->eventTypes = 0; /* None */
1840 ioc->eventContext = 0;
1841 ioc->eventLogSize = 0;
1842 ioc->events = NULL;
1843
1844#ifdef MFCNT
1845 ioc->mfcnt = 0;
1846#endif
1847
Kashyap, Desai2f187862009-05-29 16:52:37 +05301848 ioc->sh = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 ioc->cached_fw = NULL;
1850
Uwe Kleine-König421f91d2010-06-11 12:17:00 +02001851 /* Initialize SCSI Config Data structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001853 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854
Michael Reed05e8ec12006-01-13 14:31:54 -06001855 /* Initialize the fc rport list head.
1856 */
1857 INIT_LIST_HEAD(&ioc->fc_rports);
1858
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 /* Find lookup slot. */
1860 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001861
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301862
1863 /* Initialize workqueue */
1864 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301865
Kashyap, Desai2f187862009-05-29 16:52:37 +05301866 snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN,
Kay Sieversaab0de22008-05-02 06:02:41 +02001867 "mpt_poll_%d", ioc->id);
Bhaktipriya Shridharb2990532016-08-31 00:33:25 +05301868 ioc->reset_work_q = alloc_workqueue(ioc->reset_work_q_name,
1869 WQ_MEM_RECLAIM, 0);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301870 if (!ioc->reset_work_q) {
1871 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1872 ioc->name);
Ewan D. Milnee8c61ec2016-02-23 09:00:12 -05001873 r = -ENOMEM;
1874 goto out_unmap_resources;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301875 }
1876
Eric Moore29dd3602007-09-14 18:46:51 -06001877 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1878 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879
Joe Lawrencec9834c72014-06-25 17:06:28 -04001880 ioc->prod_name = mpt_get_product_name(pdev->vendor, pdev->device,
1881 pdev->revision);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301882
1883 switch (pdev->device)
1884 {
1885 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1886 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1887 ioc->errata_flag_1064 = 1;
1888 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1889 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1890 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1891 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301893 break;
1894
1895 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Sergei Shtylyov9ceb5c12012-05-31 16:26:06 -07001896 if (pdev->revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 /* 929X Chip Fix. Set Split transactions level
1898 * for PCIX. Set MOST bits to zero.
1899 */
1900 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1901 pcixcmd &= 0x8F;
1902 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1903 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 /* 929XL Chip Fix. Set MMRBC to 0x08.
1905 */
1906 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1907 pcixcmd |= 0x08;
1908 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1909 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301911 break;
1912
1913 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 /* 919X Chip Fix. Set Split transactions level
1915 * for PCIX. Set MOST bits to zero.
1916 */
1917 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1918 pcixcmd &= 0x8F;
1919 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001920 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301921 break;
1922
1923 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 /* 1030 Chip Fix. Disable Split transactions
1925 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1926 */
Sergei Shtylyov9ceb5c12012-05-31 16:26:06 -07001927 if (pdev->revision < C0_1030) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1929 pcixcmd &= 0x8F;
1930 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1931 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301932
1933 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001934 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301935 break;
1936
1937 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1938 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001939 ioc->errata_flag_1064 = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301940 ioc->bus_type = SAS;
1941 break;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301942
1943 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1944 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1945 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001946 ioc->bus_type = SAS;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301947 break;
Eric Moore87cf8982006-06-27 16:09:26 -06001948 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301950
Kashyap, Desaie3829682009-01-08 14:27:16 +05301951 switch (ioc->bus_type) {
1952
1953 case SAS:
1954 ioc->msi_enable = mpt_msi_enable_sas;
1955 break;
1956
1957 case SPI:
1958 ioc->msi_enable = mpt_msi_enable_spi;
1959 break;
1960
1961 case FC:
1962 ioc->msi_enable = mpt_msi_enable_fc;
1963 break;
1964
1965 default:
1966 ioc->msi_enable = 0;
1967 break;
1968 }
Kashyap, Desai8ce13de2010-06-17 14:35:46 +05301969
1970 ioc->fw_events_off = 1;
1971
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001972 if (ioc->errata_flag_1064)
1973 pci_disable_io_access(pdev);
1974
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 spin_lock_init(&ioc->FreeQlock);
1976
1977 /* Disable all! */
1978 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1979 ioc->active = 0;
1980 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1981
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301982 /* Set IOC ptr in the pcidev's driver data. */
1983 pci_set_drvdata(ioc->pcidev, ioc);
1984
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 /* Set lookup ptr. */
1986 list_add_tail(&ioc->list, &ioc_list);
1987
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001988 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 */
1990 mpt_detect_bound_ports(ioc, pdev);
1991
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301992 INIT_LIST_HEAD(&ioc->fw_event_list);
1993 spin_lock_init(&ioc->fw_event_lock);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301994 snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
Bhaktipriya Shridharb2990532016-08-31 00:33:25 +05301995 ioc->fw_event_q = alloc_workqueue(ioc->fw_event_q_name,
1996 WQ_MEM_RECLAIM, 0);
Ewan D. Milnee8c61ec2016-02-23 09:00:12 -05001997 if (!ioc->fw_event_q) {
1998 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1999 ioc->name);
2000 r = -ENOMEM;
2001 goto out_remove_ioc;
2002 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05302003
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
Ewan D. Milnee8c61ec2016-02-23 09:00:12 -05002009 destroy_workqueue(ioc->fw_event_q);
2010 ioc->fw_event_q = NULL;
2011
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07002013 if (ioc->alt_ioc)
2014 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302015 iounmap(ioc->memmap);
Ewan D. Milnee8c61ec2016-02-23 09:00:12 -05002016 if (pci_is_enabled(pdev))
2017 pci_disable_device(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302018 if (r != -5)
2019 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302020
2021 destroy_workqueue(ioc->reset_work_q);
2022 ioc->reset_work_q = NULL;
2023
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 return r;
2026 }
2027
2028 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002029 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302030 if(MptDeviceDriverHandlers[cb_idx] &&
2031 MptDeviceDriverHandlers[cb_idx]->probe) {
2032 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 }
2034 }
2035
2036#ifdef CONFIG_PROC_FS
2037 /*
2038 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
2039 */
2040 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
2041 if (dent) {
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07002042 proc_create_data("info", S_IRUGO, dent, &mpt_iocinfo_proc_fops, ioc);
2043 proc_create_data("summary", S_IRUGO, dent, &mpt_summary_proc_fops, ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 }
2045#endif
2046
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302047 if (!ioc->alt_ioc)
2048 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
2049 msecs_to_jiffies(MPT_POLLING_INTERVAL));
2050
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 return 0;
Ewan D. Milnee8c61ec2016-02-23 09:00:12 -05002052
2053out_remove_ioc:
2054 list_del(&ioc->list);
2055 if (ioc->alt_ioc)
2056 ioc->alt_ioc->alt_ioc = NULL;
2057
2058 destroy_workqueue(ioc->reset_work_q);
2059 ioc->reset_work_q = NULL;
2060
2061out_unmap_resources:
2062 iounmap(ioc->memmap);
2063 pci_disable_device(pdev);
2064 pci_release_selected_regions(pdev, ioc->bars);
2065
2066out_free_ioc:
2067 kfree(ioc);
2068
2069 return r;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070}
2071
2072/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002073/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002074 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 */
2077
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002078void
2079mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080{
2081 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2082 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302083 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302084 unsigned long flags;
2085 struct workqueue_struct *wq;
2086
2087 /*
2088 * Stop polling ioc for fault condition
2089 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302090 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302091 wq = ioc->reset_work_q;
2092 ioc->reset_work_q = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302093 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302094 cancel_delayed_work(&ioc->fault_reset_work);
2095 destroy_workqueue(wq);
2096
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05302097 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2098 wq = ioc->fw_event_q;
2099 ioc->fw_event_q = NULL;
2100 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2101 destroy_workqueue(wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102
2103 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2104 remove_proc_entry(pname, NULL);
2105 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2106 remove_proc_entry(pname, NULL);
2107 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2108 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002109
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002111 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302112 if(MptDeviceDriverHandlers[cb_idx] &&
2113 MptDeviceDriverHandlers[cb_idx]->remove) {
2114 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 }
2116 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002117
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 /* Disable interrupts! */
2119 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2120
2121 ioc->active = 0;
2122 synchronize_irq(pdev->irq);
2123
2124 /* Clear any lingering interrupt */
2125 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2126
2127 CHIPREG_READ32(&ioc->chip->IntStatus);
2128
2129 mpt_adapter_dispose(ioc);
2130
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131}
2132
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133/**************************************************************************
2134 * Power Management
2135 */
2136#ifdef CONFIG_PM
2137/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002138/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002139 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002140 * @pdev: Pointer to pci_dev structure
2141 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002143int
2144mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145{
2146 u32 device_state;
2147 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302149 device_state = pci_choose_state(pdev, state);
2150 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2151 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2152 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153
2154 /* put ioc into READY_STATE */
2155 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2156 printk(MYIOC_s_ERR_FMT
2157 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2158 }
2159
2160 /* disable interrupts */
2161 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2162 ioc->active = 0;
2163
2164 /* Clear any lingering interrupt */
2165 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2166
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302167 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002168 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302169 pci_disable_msi(ioc->pcidev);
2170 ioc->pci_irq = -1;
2171 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302173 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 return 0;
2176}
2177
2178/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002179/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002180 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002181 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002183int
2184mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185{
2186 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2187 u32 device_state = pdev->current_state;
2188 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302189 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002190
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302191 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2192 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2193 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302195 pci_set_power_state(pdev, PCI_D0);
2196 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302198 ioc->pcidev = pdev;
2199 err = mpt_mapresources(ioc);
2200 if (err)
2201 return err;
2202
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302203 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2204 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2205 ioc->add_sge = &mpt_add_sge_64bit_1078;
2206 else
2207 ioc->add_sge = &mpt_add_sge_64bit;
2208 ioc->add_chain = &mpt_add_chain_64bit;
2209 ioc->sg_addr_size = 8;
2210 } else {
2211
2212 ioc->add_sge = &mpt_add_sge;
2213 ioc->add_chain = &mpt_add_chain;
2214 ioc->sg_addr_size = 4;
2215 }
2216 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2217
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302218 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2219 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2220 CHIPREG_READ32(&ioc->chip->Doorbell));
2221
2222 /*
2223 * Errata workaround for SAS pci express:
2224 * Upon returning to the D0 state, the contents of the doorbell will be
2225 * stale data, and this will incorrectly signal to the host driver that
2226 * the firmware is ready to process mpt commands. The workaround is
2227 * to issue a diagnostic reset.
2228 */
2229 if (ioc->bus_type == SAS && (pdev->device ==
2230 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2231 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2232 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2233 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2234 ioc->name);
2235 goto out;
2236 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302237 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238
2239 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302240 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2241 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2242 CAN_SLEEP);
2243 if (recovery_state != 0)
2244 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2245 "error:[%x]\n", ioc->name, recovery_state);
2246 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302248 "pci-resume: success\n", ioc->name);
2249 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302251
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252}
2253#endif
2254
James Bottomley4ff42a62006-05-17 18:06:52 -05002255static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302256mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002257{
2258 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2259 ioc->bus_type != SPI) ||
2260 (MptDriverClass[index] == MPTFC_DRIVER &&
2261 ioc->bus_type != FC) ||
2262 (MptDriverClass[index] == MPTSAS_DRIVER &&
2263 ioc->bus_type != SAS))
2264 /* make sure we only call the relevant reset handler
2265 * for the bus */
2266 return 0;
2267 return (MptResetHandlers[index])(ioc, reset_phase);
2268}
2269
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002271/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2273 * @ioc: Pointer to MPT adapter structure
2274 * @reason: Event word / reason
2275 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2276 *
2277 * This routine performs all the steps necessary to bring the IOC
2278 * to a OPERATIONAL state.
2279 *
2280 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2281 * MPT adapter.
2282 *
2283 * Returns:
2284 * 0 for success
2285 * -1 if failed to get board READY
2286 * -2 if READY but IOCFacts Failed
2287 * -3 if READY but PrimeIOCFifos Failed
2288 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302289 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302290 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 */
2292static int
2293mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2294{
2295 int hard_reset_done = 0;
2296 int alt_ioc_ready = 0;
2297 int hard;
2298 int rc=0;
2299 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 int ret = 0;
2301 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002302 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302303 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304
Eric Moore29dd3602007-09-14 18:46:51 -06002305 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2306 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307
2308 /* Disable reply interrupts (also blocks FreeQ) */
2309 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2310 ioc->active = 0;
2311
2312 if (ioc->alt_ioc) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302313 if (ioc->alt_ioc->active ||
2314 reason == MPT_HOSTEVENT_IOC_RECOVER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 reset_alt_ioc_active = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302316 /* Disable alt-IOC's reply interrupts
2317 * (and FreeQ) for a bit
2318 **/
2319 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2320 0xFFFFFFFF);
2321 ioc->alt_ioc->active = 0;
2322 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 }
2324
2325 hard = 1;
2326 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2327 hard = 0;
2328
2329 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2330 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002331 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2332 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333
2334 if (reset_alt_ioc_active && ioc->alt_ioc) {
2335 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002336 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2337 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002338 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 ioc->alt_ioc->active = 1;
2340 }
2341
2342 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302343 printk(MYIOC_s_WARN_FMT
2344 "NOT READY WARNING!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302346 ret = -1;
2347 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 }
2349
2350 /* hard_reset_done = 0 if a soft reset was performed
2351 * and 1 if a hard reset was performed.
2352 */
2353 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2354 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2355 alt_ioc_ready = 1;
2356 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05302357 printk(MYIOC_s_WARN_FMT
2358 ": alt-ioc Not ready WARNING!\n",
2359 ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 }
2361
2362 for (ii=0; ii<5; ii++) {
2363 /* Get IOC facts! Allow 5 retries */
2364 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2365 break;
2366 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002367
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368
2369 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002370 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2371 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 ret = -2;
2373 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2374 MptDisplayIocCapabilities(ioc);
2375 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002376
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 if (alt_ioc_ready) {
2378 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302379 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302380 "Initial Alt IocFacts failed rc=%x\n",
2381 ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 /* Retry - alt IOC was initialized once
2383 */
2384 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2385 }
2386 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302387 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002388 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 alt_ioc_ready = 0;
2390 reset_alt_ioc_active = 0;
2391 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2392 MptDisplayIocCapabilities(ioc->alt_ioc);
2393 }
2394 }
2395
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302396 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2397 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2398 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2399 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2400 IORESOURCE_IO);
2401 if (pci_enable_device(ioc->pcidev))
2402 return -5;
2403 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2404 "mpt"))
2405 return -5;
2406 }
2407
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002408 /*
2409 * Device is reset now. It must have de-asserted the interrupt line
2410 * (if it was asserted) and it should be safe to register for the
2411 * interrupt now.
2412 */
2413 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2414 ioc->pci_irq = -1;
2415 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302416 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002417 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002418 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302419 else
2420 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002421 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002422 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002423 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002424 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Kashyap, Desai2f187862009-05-29 16:52:37 +05302425 "interrupt %d!\n",
2426 ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302427 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002428 pci_disable_msi(ioc->pcidev);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302429 ret = -EBUSY;
2430 goto out;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002431 }
2432 irq_allocated = 1;
2433 ioc->pci_irq = ioc->pcidev->irq;
2434 pci_set_master(ioc->pcidev); /* ?? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302435 pci_set_drvdata(ioc->pcidev, ioc);
2436 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2437 "installed at interrupt %d\n", ioc->name,
2438 ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002439 }
2440 }
2441
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 /* Prime reply & request queues!
2443 * (mucho alloc's) Must be done prior to
2444 * init as upper addresses are needed for init.
2445 * If fails, continue with alt-ioc processing
2446 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302447 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
2448 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2450 ret = -3;
2451
2452 /* May need to check/upload firmware & data here!
2453 * If fails, continue with alt-ioc processing
2454 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302455 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
2456 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2458 ret = -4;
2459// NEW!
2460 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302461 printk(MYIOC_s_WARN_FMT
2462 ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002463 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 alt_ioc_ready = 0;
2465 reset_alt_ioc_active = 0;
2466 }
2467
2468 if (alt_ioc_ready) {
2469 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2470 alt_ioc_ready = 0;
2471 reset_alt_ioc_active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302472 printk(MYIOC_s_WARN_FMT
2473 ": alt-ioc: (%d) init failure WARNING!\n",
2474 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 }
2476 }
2477
2478 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2479 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302480 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002481 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482
2483 /* Controller is not operational, cannot do upload
2484 */
2485 if (ret == 0) {
2486 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002487 if (rc == 0) {
2488 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2489 /*
2490 * Maintain only one pointer to FW memory
2491 * so there will not be two attempt to
2492 * downloadboot onboard dual function
2493 * chips (mpt_adapter_disable,
2494 * mpt_diag_reset)
2495 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302496 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002497 "mpt_upload: alt_%s has cached_fw=%p \n",
2498 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302499 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002500 }
2501 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002502 printk(MYIOC_s_WARN_FMT
2503 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302504 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 }
2507 }
2508 }
2509
Kashyap, Desaifd761752009-05-29 16:39:06 +05302510 /* Enable MPT base driver management of EventNotification
2511 * and EventAck handling.
2512 */
2513 if ((ret == 0) && (!ioc->facts.EventState)) {
2514 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2515 "SendEventNotification\n",
2516 ioc->name));
2517 ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
2518 }
2519
2520 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2521 rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
2522
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 if (ret == 0) {
2524 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002525 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 ioc->active = 1;
2527 }
Kashyap, Desaifd761752009-05-29 16:39:06 +05302528 if (rc == 0) { /* alt ioc */
2529 if (reset_alt_ioc_active && ioc->alt_ioc) {
2530 /* (re)Enable alt-IOC! (reply interrupt) */
2531 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
2532 "reply irq re-enabled\n",
2533 ioc->alt_ioc->name));
2534 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2535 MPI_HIM_DIM);
2536 ioc->alt_ioc->active = 1;
2537 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 }
2539
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002541 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2543 * recursive scenario; GetLanConfigPages times out, timer expired
2544 * routine calls HardResetHandler, which calls into here again,
2545 * and we try GetLanConfigPages again...
2546 */
2547 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002548
2549 /*
Uwe Kleine-König421f91d2010-06-11 12:17:00 +02002550 * Initialize link list for inactive raid volumes.
Eric Mooreb506ade2007-01-29 09:45:37 -07002551 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002552 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002553 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2554
Kashyap, Desai2f187862009-05-29 16:52:37 +05302555 switch (ioc->bus_type) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002556
Kashyap, Desai2f187862009-05-29 16:52:37 +05302557 case SAS:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002558 /* clear persistency table */
2559 if(ioc->facts.IOCExceptions &
2560 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2561 ret = mptbase_sas_persist_operation(ioc,
2562 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2563 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002564 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002565 }
2566
2567 /* Find IM volumes
2568 */
2569 mpt_findImVolumes(ioc);
2570
Kashyap, Desai2f187862009-05-29 16:52:37 +05302571 /* Check, and possibly reset, the coalescing value
2572 */
2573 mpt_read_ioc_pg_1(ioc);
2574
2575 break;
2576
2577 case FC:
2578 if ((ioc->pfacts[0].ProtocolFlags &
2579 MPI_PORTFACTS_PROTOCOL_LAN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2581 /*
2582 * Pre-fetch the ports LAN MAC address!
2583 * (LANPage1_t stuff)
2584 */
2585 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302586 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2587 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302588 "LanAddr = %02X:%02X:%02X"
2589 ":%02X:%02X:%02X\n",
2590 ioc->name, a[5], a[4],
2591 a[3], a[2], a[1], a[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302593 break;
2594
2595 case SPI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 /* Get NVRAM and adapter maximums from SPP 0 and 2
2597 */
2598 mpt_GetScsiPortSettings(ioc, 0);
2599
2600 /* Get version and length of SDP 1
2601 */
2602 mpt_readScsiDevicePageHeaders(ioc, 0);
2603
2604 /* Find IM volumes
2605 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002606 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 mpt_findImVolumes(ioc);
2608
2609 /* Check, and possibly reset, the coalescing value
2610 */
2611 mpt_read_ioc_pg_1(ioc);
2612
2613 mpt_read_ioc_pg_4(ioc);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302614
2615 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 }
2617
2618 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302619 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 }
2621
Eric Moore0ccdb002006-07-11 17:33:13 -06002622 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002623 if ((ret != 0) && irq_allocated) {
2624 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302625 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002626 pci_disable_msi(ioc->pcidev);
2627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 return ret;
2629}
2630
2631/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002632/**
2633 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 * @ioc: Pointer to MPT adapter structure
2635 * @pdev: Pointer to (struct pci_dev) structure
2636 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002637 * Search for PCI bus/dev_function which matches
2638 * PCI bus/dev_function (+/-1) for newly discovered 929,
2639 * 929X, 1030 or 1035.
2640 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2642 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2643 */
2644static void
2645mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2646{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002647 struct pci_dev *peer=NULL;
2648 unsigned int slot = PCI_SLOT(pdev->devfn);
2649 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 MPT_ADAPTER *ioc_srch;
2651
Prakash, Sathya436ace72007-07-24 15:42:08 +05302652 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002653 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002654 ioc->name, pci_name(pdev), pdev->bus->number,
2655 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002656
2657 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2658 if (!peer) {
2659 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2660 if (!peer)
2661 return;
2662 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663
2664 list_for_each_entry(ioc_srch, &ioc_list, list) {
2665 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002666 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 /* Paranoia checks */
2668 if (ioc->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302669 printk(MYIOC_s_WARN_FMT
2670 "Oops, already bound (%s <==> %s)!\n",
2671 ioc->name, ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 break;
2673 } else if (ioc_srch->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302674 printk(MYIOC_s_WARN_FMT
2675 "Oops, already bound (%s <==> %s)!\n",
2676 ioc_srch->name, ioc_srch->name,
2677 ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 break;
2679 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302680 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2681 "FOUND! binding %s <==> %s\n",
2682 ioc->name, ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 ioc_srch->alt_ioc = ioc;
2684 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 }
2686 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002687 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688}
2689
2690/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002691/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002693 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 */
2695static void
2696mpt_adapter_disable(MPT_ADAPTER *ioc)
2697{
2698 int sz;
2699 int ret;
2700
2701 if (ioc->cached_fw != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302702 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2703 "%s: Pushing FW onto adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302704 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2705 ioc->cached_fw, CAN_SLEEP)) < 0) {
2706 printk(MYIOC_s_WARN_FMT
2707 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002708 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 }
2710 }
2711
Kashyap, Desai71278192009-05-29 16:53:14 +05302712 /*
2713 * Put the controller into ready state (if its not already)
2714 */
2715 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {
2716 if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
2717 CAN_SLEEP)) {
2718 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)
2719 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit "
2720 "reset failed to put ioc in ready state!\n",
2721 ioc->name, __func__);
2722 } else
2723 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset "
2724 "failed!\n", ioc->name, __func__);
2725 }
2726
2727
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 /* Disable adapter interrupts! */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302729 synchronize_irq(ioc->pcidev->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2731 ioc->active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302732
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 /* Clear any lingering interrupt */
2734 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302735 CHIPREG_READ32(&ioc->chip->IntStatus);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736
2737 if (ioc->alloc != NULL) {
2738 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002739 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2740 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 pci_free_consistent(ioc->pcidev, sz,
2742 ioc->alloc, ioc->alloc_dma);
2743 ioc->reply_frames = NULL;
2744 ioc->req_frames = NULL;
2745 ioc->alloc = NULL;
2746 ioc->alloc_total -= sz;
2747 }
2748
2749 if (ioc->sense_buf_pool != NULL) {
2750 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2751 pci_free_consistent(ioc->pcidev, sz,
2752 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2753 ioc->sense_buf_pool = NULL;
2754 ioc->alloc_total -= sz;
2755 }
2756
2757 if (ioc->events != NULL){
2758 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2759 kfree(ioc->events);
2760 ioc->events = NULL;
2761 ioc->alloc_total -= sz;
2762 }
2763
Prakash, Sathya984621b2008-01-11 14:42:17 +05302764 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002766 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002767 mpt_inactive_raid_list_free(ioc);
2768 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002769 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002770 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002771 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772
2773 if (ioc->spi_data.pIocPg4 != NULL) {
2774 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302775 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 ioc->spi_data.pIocPg4,
2777 ioc->spi_data.IocPg4_dma);
2778 ioc->spi_data.pIocPg4 = NULL;
2779 ioc->alloc_total -= sz;
2780 }
2781
2782 if (ioc->ReqToChain != NULL) {
2783 kfree(ioc->ReqToChain);
2784 kfree(ioc->RequestNB);
2785 ioc->ReqToChain = NULL;
2786 }
2787
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002788 kfree(ioc->ChainToChain);
2789 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002790
2791 if (ioc->HostPageBuffer != NULL) {
2792 if((ret = mpt_host_page_access_control(ioc,
2793 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002794 printk(MYIOC_s_ERR_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302795 ": %s: host page buffers free failed (%d)!\n",
2796 ioc->name, __func__, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002797 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302798 dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2799 "HostPageBuffer free @ %p, sz=%d bytes\n",
2800 ioc->name, ioc->HostPageBuffer,
2801 ioc->HostPageBuffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002802 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002803 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002804 ioc->HostPageBuffer = NULL;
2805 ioc->HostPageBuffer_sz = 0;
2806 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2807 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808
Kashyap, Desai2f187862009-05-29 16:52:37 +05302809 pci_set_drvdata(ioc->pcidev, NULL);
2810}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002812/**
2813 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 * @ioc: Pointer to MPT adapter structure
2815 *
2816 * This routine unregisters h/w resources and frees all alloc'd memory
2817 * associated with a MPT adapter structure.
2818 */
2819static void
2820mpt_adapter_dispose(MPT_ADAPTER *ioc)
2821{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002822 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002824 if (ioc == NULL)
2825 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002827 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002829 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002831 if (ioc->pci_irq != -1) {
2832 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302833 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002834 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002835 ioc->pci_irq = -1;
2836 }
2837
2838 if (ioc->memmap != NULL) {
2839 iounmap(ioc->memmap);
2840 ioc->memmap = NULL;
2841 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302843 pci_disable_device(ioc->pcidev);
2844 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2845
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002846 /* Zap the adapter lookup ptr! */
2847 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002849 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002850 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2851 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002852
2853 if (ioc->alt_ioc)
2854 ioc->alt_ioc->alt_ioc = NULL;
2855
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002856 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857}
2858
2859/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002860/**
2861 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 * @ioc: Pointer to MPT adapter structure
2863 */
2864static void
2865MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2866{
2867 int i = 0;
2868
2869 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302870 if (ioc->prod_name)
2871 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 printk("Capabilities={");
2873
2874 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2875 printk("Initiator");
2876 i++;
2877 }
2878
2879 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2880 printk("%sTarget", i ? "," : "");
2881 i++;
2882 }
2883
2884 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2885 printk("%sLAN", i ? "," : "");
2886 i++;
2887 }
2888
2889#if 0
2890 /*
2891 * This would probably evoke more questions than it's worth
2892 */
2893 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2894 printk("%sLogBusAddr", i ? "," : "");
2895 i++;
2896 }
2897#endif
2898
2899 printk("}\n");
2900}
2901
2902/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002903/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2905 * @ioc: Pointer to MPT_ADAPTER structure
2906 * @force: Force hard KickStart of IOC
2907 * @sleepFlag: Specifies whether the process can sleep
2908 *
2909 * Returns:
2910 * 1 - DIAG reset and READY
2911 * 0 - READY initially OR soft reset and READY
2912 * -1 - Any failure on KickStart
2913 * -2 - Msg Unit Reset Failed
2914 * -3 - IO Unit Reset Failed
2915 * -4 - IOC owned by a PEER
2916 */
2917static int
2918MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2919{
2920 u32 ioc_state;
2921 int statefault = 0;
2922 int cntdn;
2923 int hard_reset_done = 0;
2924 int r;
2925 int ii;
2926 int whoinit;
2927
2928 /* Get current [raw] IOC state */
2929 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002930 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931
2932 /*
2933 * Check to see if IOC got left/stuck in doorbell handshake
2934 * grip of death. If so, hard reset the IOC.
2935 */
2936 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2937 statefault = 1;
2938 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2939 ioc->name);
2940 }
2941
2942 /* Is it already READY? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302943 if (!statefault &&
2944 ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) {
2945 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2946 "IOC is in READY state\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 return 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302948 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949
2950 /*
2951 * Check to see if IOC is in FAULT state.
2952 */
2953 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2954 statefault = 2;
2955 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002956 ioc->name);
2957 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2958 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 }
2960
2961 /*
2962 * Hmmm... Did it get left operational?
2963 */
2964 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302965 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 ioc->name));
2967
2968 /* Check WhoInit.
2969 * If PCI Peer, exit.
2970 * Else, if no fault conditions are present, issue a MessageUnitReset
2971 * Else, fall through to KickStart case
2972 */
2973 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002974 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2975 "whoinit 0x%x statefault %d force %d\n",
2976 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 if (whoinit == MPI_WHOINIT_PCI_PEER)
2978 return -4;
2979 else {
2980 if ((statefault == 0 ) && (force == 0)) {
2981 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2982 return 0;
2983 }
2984 statefault = 3;
2985 }
2986 }
2987
2988 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2989 if (hard_reset_done < 0)
2990 return -1;
2991
2992 /*
2993 * Loop here waiting for IOC to come READY.
2994 */
2995 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002996 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997
2998 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2999 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
3000 /*
3001 * BIOS or previous driver load left IOC in OP state.
3002 * Reset messaging FIFOs.
3003 */
3004 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
3005 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
3006 return -2;
3007 }
3008 } else if (ioc_state == MPI_IOC_STATE_RESET) {
3009 /*
3010 * Something is wrong. Try to get IOC back
3011 * to a known state.
3012 */
3013 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
3014 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
3015 return -3;
3016 }
3017 }
3018
3019 ii++; cntdn--;
3020 if (!cntdn) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303021 printk(MYIOC_s_ERR_FMT
3022 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
3023 ioc->name, ioc_state, (int)((ii+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 return -ETIME;
3025 }
3026
3027 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003028 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 } else {
3030 mdelay (1); /* 1 msec delay */
3031 }
3032
3033 }
3034
3035 if (statefault < 3) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303036 printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name,
3037 statefault == 1 ? "stuck handshake" : "IOC FAULT");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 }
3039
3040 return hard_reset_done;
3041}
3042
3043/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003044/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 * mpt_GetIocState - Get the current state of a MPT adapter.
3046 * @ioc: Pointer to MPT_ADAPTER structure
3047 * @cooked: Request raw or cooked IOC state
3048 *
3049 * Returns all IOC Doorbell register bits if cooked==0, else just the
3050 * Doorbell bits in MPI_IOC_STATE_MASK.
3051 */
3052u32
3053mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
3054{
3055 u32 s, sc;
3056
3057 /* Get! */
3058 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 sc = s & MPI_IOC_STATE_MASK;
3060
3061 /* Save! */
3062 ioc->last_state = sc;
3063
3064 return cooked ? sc : s;
3065}
3066
3067/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003068/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 * GetIocFacts - Send IOCFacts request to MPT adapter.
3070 * @ioc: Pointer to MPT_ADAPTER structure
3071 * @sleepFlag: Specifies whether the process can sleep
3072 * @reason: If recovery, only update facts.
3073 *
3074 * Returns 0 for success, non-zero for failure.
3075 */
3076static int
3077GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
3078{
3079 IOCFacts_t get_facts;
3080 IOCFactsReply_t *facts;
3081 int r;
3082 int req_sz;
3083 int reply_sz;
3084 int sz;
3085 u32 status, vv;
3086 u8 shiftFactor=1;
3087
3088 /* IOC *must* NOT be in RESET state! */
3089 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303090 printk(KERN_ERR MYNAM
3091 ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
3092 ioc->name, ioc->last_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 return -44;
3094 }
3095
3096 facts = &ioc->facts;
3097
3098 /* Destination (reply area)... */
3099 reply_sz = sizeof(*facts);
3100 memset(facts, 0, reply_sz);
3101
3102 /* Request area (get_facts on the stack right now!) */
3103 req_sz = sizeof(get_facts);
3104 memset(&get_facts, 0, req_sz);
3105
3106 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
3107 /* Assert: All other get_facts fields are zero! */
3108
Prakash, Sathya436ace72007-07-24 15:42:08 +05303109 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003110 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 ioc->name, req_sz, reply_sz));
3112
3113 /* No non-zero fields in the get_facts request are greater than
3114 * 1 byte in size, so we can just fire it off as is.
3115 */
3116 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3117 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3118 if (r != 0)
3119 return r;
3120
3121 /*
3122 * Now byte swap (GRRR) the necessary fields before any further
3123 * inspection of reply contents.
3124 *
3125 * But need to do some sanity checks on MsgLength (byte) field
3126 * to make sure we don't zero IOC's req_sz!
3127 */
3128 /* Did we get a valid reply? */
3129 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3130 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3131 /*
3132 * If not been here, done that, save off first WhoInit value
3133 */
3134 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3135 ioc->FirstWhoInit = facts->WhoInit;
3136 }
3137
3138 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3139 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3140 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3141 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3142 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003143 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 /* CHECKME! IOCStatus, IOCLogInfo */
3145
3146 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3147 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3148
3149 /*
3150 * FC f/w version changed between 1.1 and 1.2
3151 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3152 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3153 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303154 if (facts->MsgVersion < MPI_VERSION_01_02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 /*
3156 * Handle old FC f/w style, convert to new...
3157 */
3158 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3159 facts->FWVersion.Word =
3160 ((oldv<<12) & 0xFF000000) |
3161 ((oldv<<8) & 0x000FFF00);
3162 } else
3163 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3164
3165 facts->ProductID = le16_to_cpu(facts->ProductID);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303166
Eric Mooreb506ade2007-01-29 09:45:37 -07003167 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3168 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3169 ioc->ir_firmware = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303170
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 facts->CurrentHostMfaHighAddr =
3172 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3173 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3174 facts->CurrentSenseBufferHighAddr =
3175 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3176 facts->CurReplyFrameSize =
3177 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003178 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179
3180 /*
3181 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3182 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3183 * to 14 in MPI-1.01.0x.
3184 */
3185 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
Kashyap, Desai2f187862009-05-29 16:52:37 +05303186 facts->MsgVersion > MPI_VERSION_01_00) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3188 }
3189
Rasmus Villemoesf6e495a2014-07-01 14:56:20 +02003190 facts->FWImageSize = ALIGN(facts->FWImageSize, 4);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003191
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 if (!facts->RequestFrameSize) {
3193 /* Something is wrong! */
3194 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3195 ioc->name);
3196 return -55;
3197 }
3198
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003199 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 vv = ((63 / (sz * 4)) + 1) & 0x03;
3201 ioc->NB_for_64_byte_frame = vv;
3202 while ( sz )
3203 {
3204 shiftFactor++;
3205 sz = sz >> 1;
3206 }
3207 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303208 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003209 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3210 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003211
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3213 /*
3214 * Set values for this IOC's request & reply frame sizes,
3215 * and request & reply queue depths...
3216 */
3217 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3218 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3219 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3220 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3221
Prakash, Sathya436ace72007-07-24 15:42:08 +05303222 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303224 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 ioc->name, ioc->req_sz, ioc->req_depth));
3226
3227 /* Get port facts! */
3228 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3229 return r;
3230 }
3231 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003232 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3234 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3235 RequestFrameSize)/sizeof(u32)));
3236 return -66;
3237 }
3238
3239 return 0;
3240}
3241
3242/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003243/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 * GetPortFacts - Send PortFacts request to MPT adapter.
3245 * @ioc: Pointer to MPT_ADAPTER structure
3246 * @portnum: Port number
3247 * @sleepFlag: Specifies whether the process can sleep
3248 *
3249 * Returns 0 for success, non-zero for failure.
3250 */
3251static int
3252GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3253{
3254 PortFacts_t get_pfacts;
3255 PortFactsReply_t *pfacts;
3256 int ii;
3257 int req_sz;
3258 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003259 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260
3261 /* IOC *must* NOT be in RESET state! */
3262 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003263 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3264 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265 return -4;
3266 }
3267
3268 pfacts = &ioc->pfacts[portnum];
3269
3270 /* Destination (reply area)... */
3271 reply_sz = sizeof(*pfacts);
3272 memset(pfacts, 0, reply_sz);
3273
3274 /* Request area (get_pfacts on the stack right now!) */
3275 req_sz = sizeof(get_pfacts);
3276 memset(&get_pfacts, 0, req_sz);
3277
3278 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3279 get_pfacts.PortNumber = portnum;
3280 /* Assert: All other get_pfacts fields are zero! */
3281
Prakash, Sathya436ace72007-07-24 15:42:08 +05303282 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283 ioc->name, portnum));
3284
3285 /* No non-zero fields in the get_pfacts request are greater than
3286 * 1 byte in size, so we can just fire it off as is.
3287 */
3288 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3289 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3290 if (ii != 0)
3291 return ii;
3292
3293 /* Did we get a valid reply? */
3294
3295 /* Now byte swap the necessary fields in the response. */
3296 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3297 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3298 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3299 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3300 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3301 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3302 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3303 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3304 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3305
Eric Moore793955f2007-01-29 09:42:20 -07003306 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3307 pfacts->MaxDevices;
3308 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3309 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3310
3311 /*
3312 * Place all the devices on channels
3313 *
3314 * (for debuging)
3315 */
3316 if (mpt_channel_mapping) {
3317 ioc->devices_per_bus = 1;
3318 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3319 }
3320
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 return 0;
3322}
3323
3324/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003325/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 * SendIocInit - Send IOCInit request to MPT adapter.
3327 * @ioc: Pointer to MPT_ADAPTER structure
3328 * @sleepFlag: Specifies whether the process can sleep
3329 *
3330 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3331 *
3332 * Returns 0 for success, non-zero for failure.
3333 */
3334static int
3335SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3336{
3337 IOCInit_t ioc_init;
3338 MPIDefaultReply_t init_reply;
3339 u32 state;
3340 int r;
3341 int count;
3342 int cntdn;
3343
3344 memset(&ioc_init, 0, sizeof(ioc_init));
3345 memset(&init_reply, 0, sizeof(init_reply));
3346
3347 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3348 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3349
3350 /* If we are in a recovery mode and we uploaded the FW image,
3351 * then this pointer is not NULL. Skip the upload a second time.
3352 * Set this flag if cached_fw set for either IOC.
3353 */
3354 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3355 ioc->upload_fw = 1;
3356 else
3357 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303358 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3360
Eric Moore793955f2007-01-29 09:42:20 -07003361 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3362 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303363
Prakash, Sathya436ace72007-07-24 15:42:08 +05303364 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003365 ioc->name, ioc->facts.MsgVersion));
3366 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3367 // set MsgVersion and HeaderVersion host driver was built with
3368 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3369 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003371 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3372 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3373 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3374 return -99;
3375 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3377
Kashyap, Desai2f187862009-05-29 16:52:37 +05303378 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 /* Save the upper 32-bits of the request
3380 * (reply) and sense buffers.
3381 */
3382 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3383 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3384 } else {
3385 /* Force 32-bit addressing */
3386 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3387 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3388 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003389
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3391 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003392 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3393 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394
Prakash, Sathya436ace72007-07-24 15:42:08 +05303395 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 ioc->name, &ioc_init));
3397
3398 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3399 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003400 if (r != 0) {
3401 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404
3405 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003406 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 */
3408
Prakash, Sathya436ace72007-07-24 15:42:08 +05303409 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003411
3412 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3413 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003415 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416
3417 /* YIKES! SUPER IMPORTANT!!!
3418 * Poll IocState until _OPERATIONAL while IOC is doing
3419 * LoopInit and TargetDiscovery!
3420 */
3421 count = 0;
3422 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3423 state = mpt_GetIocState(ioc, 1);
3424 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3425 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003426 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 } else {
3428 mdelay(1);
3429 }
3430
3431 if (!cntdn) {
3432 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3433 ioc->name, (int)((count+5)/HZ));
3434 return -9;
3435 }
3436
3437 state = mpt_GetIocState(ioc, 1);
3438 count++;
3439 }
Eric Moore29dd3602007-09-14 18:46:51 -06003440 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441 ioc->name, count));
3442
Eric Mooreba856d32006-07-11 17:34:01 -06003443 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 return r;
3445}
3446
3447/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003448/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 * SendPortEnable - Send PortEnable request to MPT adapter port.
3450 * @ioc: Pointer to MPT_ADAPTER structure
3451 * @portnum: Port number to enable
3452 * @sleepFlag: Specifies whether the process can sleep
3453 *
3454 * Send PortEnable to bring IOC to OPERATIONAL state.
3455 *
3456 * Returns 0 for success, non-zero for failure.
3457 */
3458static int
3459SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3460{
3461 PortEnable_t port_enable;
3462 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003463 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 int req_sz;
3465 int reply_sz;
3466
3467 /* Destination... */
3468 reply_sz = sizeof(MPIDefaultReply_t);
3469 memset(&reply_buf, 0, reply_sz);
3470
3471 req_sz = sizeof(PortEnable_t);
3472 memset(&port_enable, 0, req_sz);
3473
3474 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3475 port_enable.PortNumber = portnum;
3476/* port_enable.ChainOffset = 0; */
3477/* port_enable.MsgFlags = 0; */
3478/* port_enable.MsgContext = 0; */
3479
Prakash, Sathya436ace72007-07-24 15:42:08 +05303480 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 ioc->name, portnum, &port_enable));
3482
3483 /* RAID FW may take a long time to enable
3484 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003485 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003486 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3487 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3488 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003489 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003490 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3491 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3492 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003494 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495}
3496
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003497/**
3498 * mpt_alloc_fw_memory - allocate firmware memory
3499 * @ioc: Pointer to MPT_ADAPTER structure
3500 * @size: total FW bytes
3501 *
3502 * If memory has already been allocated, the same (cached) value
3503 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303504 *
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003505 * Return 0 if successful, or non-zero for failure
Prakash, Sathya984621b2008-01-11 14:42:17 +05303506 **/
3507int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3509{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303510 int rc;
3511
3512 if (ioc->cached_fw) {
3513 rc = 0; /* use already allocated memory */
3514 goto out;
3515 }
3516 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3518 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303519 rc = 0;
3520 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303522 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3523 if (!ioc->cached_fw) {
3524 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3525 ioc->name);
3526 rc = -1;
3527 } else {
3528 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3529 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3530 ioc->alloc_total += size;
3531 rc = 0;
3532 }
3533 out:
3534 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303536
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003537/**
3538 * mpt_free_fw_memory - free firmware memory
3539 * @ioc: Pointer to MPT_ADAPTER structure
3540 *
3541 * If alt_img is NULL, delete from ioc structure.
3542 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303543 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544void
3545mpt_free_fw_memory(MPT_ADAPTER *ioc)
3546{
3547 int sz;
3548
Prakash, Sathya984621b2008-01-11 14:42:17 +05303549 if (!ioc->cached_fw)
3550 return;
3551
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303553 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3554 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003555 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303556 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558}
3559
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003561/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3563 * @ioc: Pointer to MPT_ADAPTER structure
3564 * @sleepFlag: Specifies whether the process can sleep
3565 *
3566 * Returns 0 for success, >0 for handshake failure
3567 * <0 for fw upload failure.
3568 *
3569 * Remark: If bound IOC and a successful FWUpload was performed
3570 * on the bound IOC, the second image is discarded
3571 * and memory is free'd. Both channels must upload to prevent
3572 * IOC from running in degraded mode.
3573 */
3574static int
3575mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3576{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 u8 reply[sizeof(FWUploadReply_t)];
3578 FWUpload_t *prequest;
3579 FWUploadReply_t *preply;
3580 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 u32 flagsLength;
3582 int ii, sz, reply_sz;
3583 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303584 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 /* If the image size is 0, we are done.
3586 */
3587 if ((sz = ioc->facts.FWImageSize) == 0)
3588 return 0;
3589
Prakash, Sathya984621b2008-01-11 14:42:17 +05303590 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3591 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592
Eric Moore29dd3602007-09-14 18:46:51 -06003593 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3594 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003595
Eric Moorebc6e0892007-09-29 10:16:28 -06003596 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3597 kzalloc(ioc->req_sz, GFP_KERNEL);
3598 if (!prequest) {
3599 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3600 "while allocating memory \n", ioc->name));
3601 mpt_free_fw_memory(ioc);
3602 return -ENOMEM;
3603 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604
Eric Moorebc6e0892007-09-29 10:16:28 -06003605 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606
3607 reply_sz = sizeof(reply);
3608 memset(preply, 0, reply_sz);
3609
3610 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3611 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3612
3613 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3614 ptcsge->DetailsLength = 12;
3615 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3616 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003617 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303620 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3621 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3622 ioc->SGE_size;
3623 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3624 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3625 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003626 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303628 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3629 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630
Kashyap, Desai2f187862009-05-29 16:52:37 +05303631 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
3632 "rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633
3634 cmdStatus = -EFAULT;
3635 if (ii == 0) {
3636 /* Handshake transfer was complete and successful.
3637 * Check the Reply Frame.
3638 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303639 int status;
3640 status = le16_to_cpu(preply->IOCStatus) &
3641 MPI_IOCSTATUS_MASK;
3642 if (status == MPI_IOCSTATUS_SUCCESS &&
3643 ioc->facts.FWImageSize ==
3644 le32_to_cpu(preply->ActualImageSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 cmdStatus = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303647 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 ioc->name, cmdStatus));
3649
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003650
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 if (cmdStatus) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303652 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
3653 "freeing image \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 mpt_free_fw_memory(ioc);
3655 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003656 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657
3658 return cmdStatus;
3659}
3660
3661/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003662/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 * mpt_downloadboot - DownloadBoot code
3664 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003665 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 * @sleepFlag: Specifies whether the process can sleep
3667 *
3668 * FwDownloadBoot requires Programmed IO access.
3669 *
3670 * Returns 0 for success
3671 * -1 FW Image size is 0
3672 * -2 No valid cached_fw Pointer
3673 * <0 for fw upload failure.
3674 */
3675static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003676mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678 MpiExtImageHeader_t *pExtImage;
3679 u32 fwSize;
3680 u32 diag0val;
3681 int count;
3682 u32 *ptrFw;
3683 u32 diagRwData;
3684 u32 nextImage;
3685 u32 load_addr;
3686 u32 ioc_state=0;
3687
Prakash, Sathya436ace72007-07-24 15:42:08 +05303688 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003689 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003690
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3692 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3693 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3694 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3695 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3696 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3697
3698 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3699
3700 /* wait 1 msec */
3701 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003702 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 } else {
3704 mdelay (1);
3705 }
3706
3707 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3708 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3709
3710 for (count = 0; count < 30; count ++) {
3711 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3712 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303713 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714 ioc->name, count));
3715 break;
3716 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003717 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003719 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003721 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722 }
3723 }
3724
3725 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303726 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003727 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728 ioc->name, diag0val));
3729 return -3;
3730 }
3731
3732 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3733 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3734 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3735 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3736 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3737 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3738
3739 /* Set the DiagRwEn and Disable ARM bits */
3740 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3741
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742 fwSize = (pFwHeader->ImageSize + 3)/4;
3743 ptrFw = (u32 *) pFwHeader;
3744
3745 /* Write the LoadStartAddress to the DiagRw Address Register
3746 * using Programmed IO
3747 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003748 if (ioc->errata_flag_1064)
3749 pci_enable_io_access(ioc->pcidev);
3750
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303752 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753 ioc->name, pFwHeader->LoadStartAddress));
3754
Prakash, Sathya436ace72007-07-24 15:42:08 +05303755 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756 ioc->name, fwSize*4, ptrFw));
3757 while (fwSize--) {
3758 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3759 }
3760
3761 nextImage = pFwHeader->NextImageHeaderOffset;
3762 while (nextImage) {
3763 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3764
3765 load_addr = pExtImage->LoadStartAddress;
3766
3767 fwSize = (pExtImage->ImageSize + 3) >> 2;
3768 ptrFw = (u32 *)pExtImage;
3769
Prakash, Sathya436ace72007-07-24 15:42:08 +05303770 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 +02003771 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3773
3774 while (fwSize--) {
3775 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3776 }
3777 nextImage = pExtImage->NextImageHeaderOffset;
3778 }
3779
3780 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303781 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3783
3784 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303785 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3787
3788 /* Clear the internal flash bad bit - autoincrementing register,
3789 * so must do two writes.
3790 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003791 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003792 /*
3793 * 1030 and 1035 H/W errata, workaround to access
3794 * the ClearFlashBadSignatureBit
3795 */
3796 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3797 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3798 diagRwData |= 0x40000000;
3799 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3800 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3801
3802 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3803 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3804 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3805 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3806
3807 /* wait 1 msec */
3808 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003809 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003810 } else {
3811 mdelay (1);
3812 }
3813 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003815 if (ioc->errata_flag_1064)
3816 pci_disable_io_access(ioc->pcidev);
3817
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303819 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003820 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003822 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303823 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 ioc->name, diag0val));
3825 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3826
3827 /* Write 0xFF to reset the sequencer */
3828 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3829
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003830 if (ioc->bus_type == SAS) {
3831 ioc_state = mpt_GetIocState(ioc, 0);
3832 if ( (GetIocFacts(ioc, sleepFlag,
3833 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303834 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003835 ioc->name, ioc_state));
3836 return -EFAULT;
3837 }
3838 }
3839
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 for (count=0; count<HZ*20; count++) {
3841 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303842 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3843 "downloadboot successful! (count=%d) IocState=%x\n",
3844 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003845 if (ioc->bus_type == SAS) {
3846 return 0;
3847 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303849 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3850 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003851 ioc->name));
3852 return -EFAULT;
3853 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303854 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3855 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856 ioc->name));
3857 return 0;
3858 }
3859 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003860 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861 } else {
3862 mdelay (10);
3863 }
3864 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303865 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3866 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867 return -EFAULT;
3868}
3869
3870/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003871/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 * KickStart - Perform hard reset of MPT adapter.
3873 * @ioc: Pointer to MPT_ADAPTER structure
3874 * @force: Force hard reset
3875 * @sleepFlag: Specifies whether the process can sleep
3876 *
3877 * This routine places MPT adapter in diagnostic mode via the
3878 * WriteSequence register, and then performs a hard reset of adapter
3879 * via the Diagnostic register.
3880 *
3881 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3882 * or NO_SLEEP (interrupt thread, use mdelay)
3883 * force - 1 if doorbell active, board fault state
3884 * board operational, IOC_RECOVERY or
3885 * IOC_BRINGUP and there is an alt_ioc.
3886 * 0 else
3887 *
3888 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003889 * 1 - hard reset, READY
3890 * 0 - no reset due to History bit, READY
3891 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892 * OR reset but failed to come READY
3893 * -2 - no reset, could not enter DIAG mode
3894 * -3 - reset but bad FW bit
3895 */
3896static int
3897KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3898{
3899 int hard_reset_done = 0;
3900 u32 ioc_state=0;
3901 int cnt,cntdn;
3902
Eric Moore29dd3602007-09-14 18:46:51 -06003903 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003904 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 /* Always issue a Msg Unit Reset first. This will clear some
3906 * SCSI bus hang conditions.
3907 */
3908 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3909
3910 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003911 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 } else {
3913 mdelay (1000);
3914 }
3915 }
3916
3917 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3918 if (hard_reset_done < 0)
3919 return hard_reset_done;
3920
Prakash, Sathya436ace72007-07-24 15:42:08 +05303921 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003922 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003923
3924 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3925 for (cnt=0; cnt<cntdn; cnt++) {
3926 ioc_state = mpt_GetIocState(ioc, 1);
3927 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303928 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929 ioc->name, cnt));
3930 return hard_reset_done;
3931 }
3932 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003933 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934 } else {
3935 mdelay (10);
3936 }
3937 }
3938
Eric Moore29dd3602007-09-14 18:46:51 -06003939 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3940 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941 return -1;
3942}
3943
3944/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003945/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003946 * mpt_diag_reset - Perform hard reset of the adapter.
3947 * @ioc: Pointer to MPT_ADAPTER structure
3948 * @ignore: Set if to honor and clear to ignore
3949 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003950 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951 * else set to NO_SLEEP (use mdelay instead)
3952 *
3953 * This routine places the adapter in diagnostic mode via the
3954 * WriteSequence register and then performs a hard reset of adapter
3955 * via the Diagnostic register. Adapter should be in ready state
3956 * upon successful completion.
3957 *
3958 * Returns: 1 hard reset successful
3959 * 0 no reset performed because reset history bit set
3960 * -2 enabling diagnostic mode failed
3961 * -3 diagnostic reset failed
3962 */
3963static int
3964mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3965{
3966 u32 diag0val;
3967 u32 doorbell;
3968 int hard_reset_done = 0;
3969 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303971 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Kashyap, Desaid1306912009-08-05 12:53:51 +05303972 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973
Eric Moorecd2c6192007-01-29 09:47:47 -07003974 /* Clear any existing interrupts */
3975 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3976
Eric Moore87cf8982006-06-27 16:09:26 -06003977 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303978
3979 if (!ignore)
3980 return 0;
3981
Prakash, Sathya436ace72007-07-24 15:42:08 +05303982 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003983 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003984 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3985 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3986 if (sleepFlag == CAN_SLEEP)
3987 msleep(1);
3988 else
3989 mdelay(1);
3990
Kashyap, Desaid1306912009-08-05 12:53:51 +05303991 /*
3992 * Call each currently registered protocol IOC reset handler
3993 * with pre-reset indication.
3994 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3995 * MptResetHandlers[] registered yet.
3996 */
3997 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3998 if (MptResetHandlers[cb_idx])
3999 (*(MptResetHandlers[cb_idx]))(ioc,
4000 MPT_IOC_PRE_RESET);
4001 }
4002
Eric Moore87cf8982006-06-27 16:09:26 -06004003 for (count = 0; count < 60; count ++) {
4004 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4005 doorbell &= MPI_IOC_STATE_MASK;
4006
Prakash, Sathya436ace72007-07-24 15:42:08 +05304007 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06004008 "looking for READY STATE: doorbell=%x"
4009 " count=%d\n",
4010 ioc->name, doorbell, count));
Kashyap, Desai2f187862009-05-29 16:52:37 +05304011
Eric Moore87cf8982006-06-27 16:09:26 -06004012 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004013 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06004014 }
4015
4016 /* wait 1 sec */
4017 if (sleepFlag == CAN_SLEEP)
4018 msleep(1000);
4019 else
4020 mdelay(1000);
4021 }
4022 return -1;
4023 }
4024
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 /* Use "Diagnostic reset" method! (only thing available!) */
4026 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4027
Prakash, Sathya436ace72007-07-24 15:42:08 +05304028 if (ioc->debug_level & MPT_DEBUG) {
4029 if (ioc->alt_ioc)
4030 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4031 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304033 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034
4035 /* Do the reset if we are told to ignore the reset history
4036 * or if the reset history is 0
4037 */
4038 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
4039 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4040 /* Write magic sequence to WriteSequence register
4041 * Loop until in diagnostic mode
4042 */
4043 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4044 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4045 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4046 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4047 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4048 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4049
4050 /* wait 100 msec */
4051 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004052 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053 } else {
4054 mdelay (100);
4055 }
4056
4057 count++;
4058 if (count > 20) {
4059 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4060 ioc->name, diag0val);
4061 return -2;
4062
4063 }
4064
4065 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4066
Prakash, Sathya436ace72007-07-24 15:42:08 +05304067 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 ioc->name, diag0val));
4069 }
4070
Prakash, Sathya436ace72007-07-24 15:42:08 +05304071 if (ioc->debug_level & MPT_DEBUG) {
4072 if (ioc->alt_ioc)
4073 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4074 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304076 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077 /*
4078 * Disable the ARM (Bug fix)
4079 *
4080 */
4081 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004082 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083
4084 /*
4085 * Now hit the reset bit in the Diagnostic register
4086 * (THE BIG HAMMER!) (Clears DRWE bit).
4087 */
4088 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
4089 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304090 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091 ioc->name));
4092
4093 /*
4094 * Call each currently registered protocol IOC reset handler
4095 * with pre-reset indication.
4096 * NOTE: If we're doing _IOC_BRINGUP, there can be no
4097 * MptResetHandlers[] registered yet.
4098 */
Kashyap, Desaid1306912009-08-05 12:53:51 +05304099 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
4100 if (MptResetHandlers[cb_idx]) {
4101 mpt_signal_reset(cb_idx,
4102 ioc, MPT_IOC_PRE_RESET);
4103 if (ioc->alt_ioc) {
4104 mpt_signal_reset(cb_idx,
4105 ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106 }
4107 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108 }
4109
Eric Moore0ccdb002006-07-11 17:33:13 -06004110 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304111 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06004112 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304113 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4114 else
4115 cached_fw = NULL;
4116 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 /* If the DownloadBoot operation fails, the
4118 * IOC will be left unusable. This is a fatal error
4119 * case. _diag_reset will return < 0
4120 */
4121 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304122 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4124 break;
4125 }
4126
Prakash, Sathya436ace72007-07-24 15:42:08 +05304127 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304128 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129 /* wait 1 sec */
4130 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004131 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132 } else {
4133 mdelay (1000);
4134 }
4135 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304136 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004137 printk(MYIOC_s_WARN_FMT
4138 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139 }
4140
4141 } else {
4142 /* Wait for FW to reload and for board
4143 * to go to the READY state.
4144 * Maximum wait is 60 seconds.
4145 * If fail, no error will check again
4146 * with calling program.
4147 */
4148 for (count = 0; count < 60; count ++) {
4149 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4150 doorbell &= MPI_IOC_STATE_MASK;
4151
Kashyap, Desai2f187862009-05-29 16:52:37 +05304152 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4153 "looking for READY STATE: doorbell=%x"
4154 " count=%d\n", ioc->name, doorbell, count));
4155
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 if (doorbell == MPI_IOC_STATE_READY) {
4157 break;
4158 }
4159
4160 /* wait 1 sec */
4161 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004162 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163 } else {
4164 mdelay (1000);
4165 }
4166 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05304167
4168 if (doorbell != MPI_IOC_STATE_READY)
4169 printk(MYIOC_s_ERR_FMT "Failed to come READY "
4170 "after reset! IocState=%x", ioc->name,
4171 doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172 }
4173 }
4174
4175 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304176 if (ioc->debug_level & MPT_DEBUG) {
4177 if (ioc->alt_ioc)
4178 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4179 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4180 ioc->name, diag0val, diag1val));
4181 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182
4183 /* Clear RESET_HISTORY bit! Place board in the
4184 * diagnostic mode to update the diag register.
4185 */
4186 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4187 count = 0;
4188 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4189 /* Write magic sequence to WriteSequence register
4190 * Loop until in diagnostic mode
4191 */
4192 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4193 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4194 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4195 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4196 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4197 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4198
4199 /* wait 100 msec */
4200 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004201 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202 } else {
4203 mdelay (100);
4204 }
4205
4206 count++;
4207 if (count > 20) {
4208 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4209 ioc->name, diag0val);
4210 break;
4211 }
4212 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4213 }
4214 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4215 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4216 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4217 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4218 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4219 ioc->name);
4220 }
4221
4222 /* Disable Diagnostic Mode
4223 */
4224 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4225
4226 /* Check FW reload status flags.
4227 */
4228 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4229 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4230 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4231 ioc->name, diag0val);
4232 return -3;
4233 }
4234
Prakash, Sathya436ace72007-07-24 15:42:08 +05304235 if (ioc->debug_level & MPT_DEBUG) {
4236 if (ioc->alt_ioc)
4237 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4238 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304240 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241
4242 /*
4243 * Reset flag that says we've enabled event notification
4244 */
4245 ioc->facts.EventState = 0;
4246
4247 if (ioc->alt_ioc)
4248 ioc->alt_ioc->facts.EventState = 0;
4249
4250 return hard_reset_done;
4251}
4252
4253/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004254/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255 * SendIocReset - Send IOCReset request to MPT adapter.
4256 * @ioc: Pointer to MPT_ADAPTER structure
4257 * @reset_type: reset type, expected values are
4258 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004259 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 *
4261 * Send IOCReset request to the MPT adapter.
4262 *
4263 * Returns 0 for success, non-zero for failure.
4264 */
4265static int
4266SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4267{
4268 int r;
4269 u32 state;
4270 int cntdn, count;
4271
Prakash, Sathya436ace72007-07-24 15:42:08 +05304272 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273 ioc->name, reset_type));
4274 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4275 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4276 return r;
4277
4278 /* FW ACK'd request, wait for READY state
4279 */
4280 count = 0;
4281 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4282
4283 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4284 cntdn--;
4285 count++;
4286 if (!cntdn) {
4287 if (sleepFlag != CAN_SLEEP)
4288 count *= 10;
4289
Kashyap, Desai2f187862009-05-29 16:52:37 +05304290 printk(MYIOC_s_ERR_FMT
4291 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
4292 ioc->name, state, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293 return -ETIME;
4294 }
4295
4296 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004297 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 } else {
4299 mdelay (1); /* 1 msec delay */
4300 }
4301 }
4302
4303 /* TODO!
4304 * Cleanup all event stuff for this IOC; re-issue EventNotification
4305 * request if needed.
4306 */
4307 if (ioc->facts.Function)
4308 ioc->facts.EventState = 0;
4309
4310 return 0;
4311}
4312
4313/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004314/**
4315 * initChainBuffers - Allocate memory for and initialize chain buffers
4316 * @ioc: Pointer to MPT_ADAPTER structure
4317 *
4318 * Allocates memory for and initializes chain buffers,
4319 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 */
4321static int
4322initChainBuffers(MPT_ADAPTER *ioc)
4323{
4324 u8 *mem;
4325 int sz, ii, num_chain;
4326 int scale, num_sge, numSGE;
4327
4328 /* ReqToChain size must equal the req_depth
4329 * index = req_idx
4330 */
4331 if (ioc->ReqToChain == NULL) {
4332 sz = ioc->req_depth * sizeof(int);
4333 mem = kmalloc(sz, GFP_ATOMIC);
4334 if (mem == NULL)
4335 return -1;
4336
4337 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304338 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339 ioc->name, mem, sz));
4340 mem = kmalloc(sz, GFP_ATOMIC);
4341 if (mem == NULL)
4342 return -1;
4343
4344 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304345 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 ioc->name, mem, sz));
4347 }
4348 for (ii = 0; ii < ioc->req_depth; ii++) {
4349 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4350 }
4351
4352 /* ChainToChain size must equal the total number
4353 * of chain buffers to be allocated.
4354 * index = chain_idx
4355 *
4356 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004357 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358 *
4359 * num_sge = num sge in request frame + last chain buffer
4360 * scale = num sge per chain buffer if no chain element
4361 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304362 scale = ioc->req_sz / ioc->SGE_size;
4363 if (ioc->sg_addr_size == sizeof(u64))
4364 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304366 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304368 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304370 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304372 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4373 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304375 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376 ioc->name, num_sge, numSGE));
4377
Kashyap, Desai2f187862009-05-29 16:52:37 +05304378 if (ioc->bus_type == FC) {
4379 if (numSGE > MPT_SCSI_FC_SG_DEPTH)
4380 numSGE = MPT_SCSI_FC_SG_DEPTH;
4381 } else {
4382 if (numSGE > MPT_SCSI_SG_DEPTH)
4383 numSGE = MPT_SCSI_SG_DEPTH;
4384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385
4386 num_chain = 1;
4387 while (numSGE - num_sge > 0) {
4388 num_chain++;
4389 num_sge += (scale - 1);
4390 }
4391 num_chain++;
4392
Prakash, Sathya436ace72007-07-24 15:42:08 +05304393 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394 ioc->name, numSGE, num_sge, num_chain));
4395
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004396 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 num_chain *= MPT_SCSI_CAN_QUEUE;
Anatolij Gustschinf1053a72009-12-12 14:52:21 +01004398 else if (ioc->bus_type == SAS)
4399 num_chain *= MPT_SAS_CAN_QUEUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400 else
4401 num_chain *= MPT_FC_CAN_QUEUE;
4402
4403 ioc->num_chain = num_chain;
4404
4405 sz = num_chain * sizeof(int);
4406 if (ioc->ChainToChain == NULL) {
4407 mem = kmalloc(sz, GFP_ATOMIC);
4408 if (mem == NULL)
4409 return -1;
4410
4411 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304412 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413 ioc->name, mem, sz));
4414 } else {
4415 mem = (u8 *) ioc->ChainToChain;
4416 }
4417 memset(mem, 0xFF, sz);
4418 return num_chain;
4419}
4420
4421/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004422/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4424 * @ioc: Pointer to MPT_ADAPTER structure
4425 *
4426 * This routine allocates memory for the MPT reply and request frame
4427 * pools (if necessary), and primes the IOC reply FIFO with
4428 * reply frames.
4429 *
4430 * Returns 0 for success, non-zero for failure.
4431 */
4432static int
4433PrimeIocFifos(MPT_ADAPTER *ioc)
4434{
4435 MPT_FRAME_HDR *mf;
4436 unsigned long flags;
4437 dma_addr_t alloc_dma;
4438 u8 *mem;
4439 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304440 u64 dma_mask;
4441
4442 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443
4444 /* Prime reply FIFO... */
4445
4446 if (ioc->reply_frames == NULL) {
4447 if ( (num_chain = initChainBuffers(ioc)) < 0)
4448 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304449 /*
4450 * 1078 errata workaround for the 36GB limitation
4451 */
4452 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
Andrew Morton8e20ce92009-06-18 16:49:17 -07004453 ioc->dma_mask > DMA_BIT_MASK(35)) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304454 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4455 && !pci_set_consistent_dma_mask(ioc->pcidev,
4456 DMA_BIT_MASK(32))) {
Andrew Morton8e20ce92009-06-18 16:49:17 -07004457 dma_mask = DMA_BIT_MASK(35);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304458 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4459 "setting 35 bit addressing for "
4460 "Request/Reply/Chain and Sense Buffers\n",
4461 ioc->name));
4462 } else {
4463 /*Reseting DMA mask to 64 bit*/
4464 pci_set_dma_mask(ioc->pcidev,
4465 DMA_BIT_MASK(64));
4466 pci_set_consistent_dma_mask(ioc->pcidev,
4467 DMA_BIT_MASK(64));
4468
4469 printk(MYIOC_s_ERR_FMT
4470 "failed setting 35 bit addressing for "
4471 "Request/Reply/Chain and Sense Buffers\n",
4472 ioc->name);
4473 return -1;
4474 }
4475 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476
4477 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304478 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304480 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 ioc->name, reply_sz, reply_sz));
4482
4483 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304484 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304486 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 ioc->name, sz, sz));
4488 total_size += sz;
4489
4490 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304491 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304493 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 ioc->name, sz, sz, num_chain));
4495
4496 total_size += sz;
4497 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4498 if (mem == NULL) {
4499 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4500 ioc->name);
4501 goto out_fail;
4502 }
4503
Prakash, Sathya436ace72007-07-24 15:42:08 +05304504 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4506
4507 memset(mem, 0, total_size);
4508 ioc->alloc_total += total_size;
4509 ioc->alloc = mem;
4510 ioc->alloc_dma = alloc_dma;
4511 ioc->alloc_sz = total_size;
4512 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4513 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4514
Prakash, Sathya436ace72007-07-24 15:42:08 +05304515 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004516 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4517
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 alloc_dma += reply_sz;
4519 mem += reply_sz;
4520
4521 /* Request FIFO - WE manage this! */
4522
4523 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4524 ioc->req_frames_dma = alloc_dma;
4525
Prakash, Sathya436ace72007-07-24 15:42:08 +05304526 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 ioc->name, mem, (void *)(ulong)alloc_dma));
4528
4529 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4530
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531 for (i = 0; i < ioc->req_depth; i++) {
4532 alloc_dma += ioc->req_sz;
4533 mem += ioc->req_sz;
4534 }
4535
4536 ioc->ChainBuffer = mem;
4537 ioc->ChainBufferDMA = alloc_dma;
4538
Prakash, Sathya436ace72007-07-24 15:42:08 +05304539 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4541
4542 /* Initialize the free chain Q.
4543 */
4544
4545 INIT_LIST_HEAD(&ioc->FreeChainQ);
4546
4547 /* Post the chain buffers to the FreeChainQ.
4548 */
4549 mem = (u8 *)ioc->ChainBuffer;
4550 for (i=0; i < num_chain; i++) {
4551 mf = (MPT_FRAME_HDR *) mem;
4552 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4553 mem += ioc->req_sz;
4554 }
4555
4556 /* Initialize Request frames linked list
4557 */
4558 alloc_dma = ioc->req_frames_dma;
4559 mem = (u8 *) ioc->req_frames;
4560
4561 spin_lock_irqsave(&ioc->FreeQlock, flags);
4562 INIT_LIST_HEAD(&ioc->FreeQ);
4563 for (i = 0; i < ioc->req_depth; i++) {
4564 mf = (MPT_FRAME_HDR *) mem;
4565
4566 /* Queue REQUESTs *internally*! */
4567 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4568
4569 mem += ioc->req_sz;
4570 }
4571 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4572
4573 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4574 ioc->sense_buf_pool =
4575 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4576 if (ioc->sense_buf_pool == NULL) {
4577 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4578 ioc->name);
4579 goto out_fail;
4580 }
4581
4582 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4583 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304584 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4586
4587 }
4588
4589 /* Post Reply frames to FIFO
4590 */
4591 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304592 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4594
4595 for (i = 0; i < ioc->reply_depth; i++) {
4596 /* Write each address to the IOC! */
4597 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4598 alloc_dma += ioc->reply_sz;
4599 }
4600
Andrew Morton8e20ce92009-06-18 16:49:17 -07004601 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304602 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4603 ioc->dma_mask))
4604 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4605 "restoring 64 bit addressing\n", ioc->name));
4606
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 return 0;
4608
4609out_fail:
Kashyap, Desai2f187862009-05-29 16:52:37 +05304610
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 if (ioc->alloc != NULL) {
4612 sz = ioc->alloc_sz;
4613 pci_free_consistent(ioc->pcidev,
4614 sz,
4615 ioc->alloc, ioc->alloc_dma);
4616 ioc->reply_frames = NULL;
4617 ioc->req_frames = NULL;
4618 ioc->alloc_total -= sz;
4619 }
4620 if (ioc->sense_buf_pool != NULL) {
4621 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4622 pci_free_consistent(ioc->pcidev,
4623 sz,
4624 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4625 ioc->sense_buf_pool = NULL;
4626 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304627
Andrew Morton8e20ce92009-06-18 16:49:17 -07004628 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304629 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4630 DMA_BIT_MASK(64)))
4631 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4632 "restoring 64 bit addressing\n", ioc->name));
4633
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 return -1;
4635}
4636
4637/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4638/**
4639 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4640 * from IOC via doorbell handshake method.
4641 * @ioc: Pointer to MPT_ADAPTER structure
4642 * @reqBytes: Size of the request in bytes
4643 * @req: Pointer to MPT request frame
4644 * @replyBytes: Expected size of the reply in bytes
4645 * @u16reply: Pointer to area where reply should be written
4646 * @maxwait: Max wait time for a reply (in seconds)
4647 * @sleepFlag: Specifies whether the process can sleep
4648 *
4649 * NOTES: It is the callers responsibility to byte-swap fields in the
4650 * request which are greater than 1 byte in size. It is also the
4651 * callers responsibility to byte-swap response fields which are
4652 * greater than 1 byte in size.
4653 *
4654 * Returns 0 for success, non-zero for failure.
4655 */
4656static int
4657mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004658 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004659{
4660 MPIDefaultReply_t *mptReply;
4661 int failcnt = 0;
4662 int t;
4663
4664 /*
4665 * Get ready to cache a handshake reply
4666 */
4667 ioc->hs_reply_idx = 0;
4668 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4669 mptReply->MsgLength = 0;
4670
4671 /*
4672 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4673 * then tell IOC that we want to handshake a request of N words.
4674 * (WRITE u32val to Doorbell reg).
4675 */
4676 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4677 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4678 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4679 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4680
4681 /*
4682 * Wait for IOC's doorbell handshake int
4683 */
4684 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4685 failcnt++;
4686
Prakash, Sathya436ace72007-07-24 15:42:08 +05304687 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4689
4690 /* Read doorbell and check for active bit */
4691 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4692 return -1;
4693
4694 /*
4695 * Clear doorbell int (WRITE 0 to IntStatus reg),
4696 * then wait for IOC to ACKnowledge that it's ready for
4697 * our handshake request.
4698 */
4699 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4700 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4701 failcnt++;
4702
4703 if (!failcnt) {
4704 int ii;
4705 u8 *req_as_bytes = (u8 *) req;
4706
4707 /*
4708 * Stuff request words via doorbell handshake,
4709 * with ACK from IOC for each.
4710 */
4711 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4712 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4713 (req_as_bytes[(ii*4) + 1] << 8) |
4714 (req_as_bytes[(ii*4) + 2] << 16) |
4715 (req_as_bytes[(ii*4) + 3] << 24));
4716
4717 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4718 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4719 failcnt++;
4720 }
4721
Prakash, Sathya436ace72007-07-24 15:42:08 +05304722 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004723 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724
Prakash, Sathya436ace72007-07-24 15:42:08 +05304725 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4727
4728 /*
4729 * Wait for completion of doorbell handshake reply from the IOC
4730 */
4731 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4732 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004733
Prakash, Sathya436ace72007-07-24 15:42:08 +05304734 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4736
4737 /*
4738 * Copy out the cached reply...
4739 */
4740 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4741 u16reply[ii] = ioc->hs_reply[ii];
4742 } else {
4743 return -99;
4744 }
4745
4746 return -failcnt;
4747}
4748
4749/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004750/**
4751 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752 * @ioc: Pointer to MPT_ADAPTER structure
4753 * @howlong: How long to wait (in seconds)
4754 * @sleepFlag: Specifies whether the process can sleep
4755 *
4756 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004757 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4758 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 *
4760 * Returns a negative value on failure, else wait loop count.
4761 */
4762static int
4763WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4764{
4765 int cntdn;
4766 int count = 0;
4767 u32 intstat=0;
4768
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004769 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770
4771 if (sleepFlag == CAN_SLEEP) {
4772 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004773 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4775 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4776 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777 count++;
4778 }
4779 } else {
4780 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004781 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4783 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4784 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785 count++;
4786 }
4787 }
4788
4789 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304790 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791 ioc->name, count));
4792 return count;
4793 }
4794
4795 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4796 ioc->name, count, intstat);
4797 return -1;
4798}
4799
4800/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004801/**
4802 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 * @ioc: Pointer to MPT_ADAPTER structure
4804 * @howlong: How long to wait (in seconds)
4805 * @sleepFlag: Specifies whether the process can sleep
4806 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004807 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4808 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 *
4810 * Returns a negative value on failure, else wait loop count.
4811 */
4812static int
4813WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4814{
4815 int cntdn;
4816 int count = 0;
4817 u32 intstat=0;
4818
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004819 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820 if (sleepFlag == CAN_SLEEP) {
4821 while (--cntdn) {
4822 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4823 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4824 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004825 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826 count++;
4827 }
4828 } else {
4829 while (--cntdn) {
4830 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4831 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4832 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004833 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834 count++;
4835 }
4836 }
4837
4838 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304839 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 ioc->name, count, howlong));
4841 return count;
4842 }
4843
4844 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4845 ioc->name, count, intstat);
4846 return -1;
4847}
4848
4849/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004850/**
4851 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 * @ioc: Pointer to MPT_ADAPTER structure
4853 * @howlong: How long to wait (in seconds)
4854 * @sleepFlag: Specifies whether the process can sleep
4855 *
4856 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4857 * Reply is cached to IOC private area large enough to hold a maximum
4858 * of 128 bytes of reply data.
4859 *
4860 * Returns a negative value on failure, else size of reply in WORDS.
4861 */
4862static int
4863WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4864{
4865 int u16cnt = 0;
4866 int failcnt = 0;
4867 int t;
4868 u16 *hs_reply = ioc->hs_reply;
4869 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4870 u16 hword;
4871
4872 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4873
4874 /*
4875 * Get first two u16's so we can look at IOC's intended reply MsgLength
4876 */
4877 u16cnt=0;
4878 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4879 failcnt++;
4880 } else {
4881 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4882 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4883 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4884 failcnt++;
4885 else {
4886 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4887 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4888 }
4889 }
4890
Prakash, Sathya436ace72007-07-24 15:42:08 +05304891 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004892 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4894
4895 /*
4896 * If no error (and IOC said MsgLength is > 0), piece together
4897 * reply 16 bits at a time.
4898 */
4899 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4900 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4901 failcnt++;
4902 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4903 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004904 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905 hs_reply[u16cnt] = hword;
4906 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4907 }
4908
4909 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4910 failcnt++;
4911 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4912
4913 if (failcnt) {
4914 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4915 ioc->name);
4916 return -failcnt;
4917 }
4918#if 0
4919 else if (u16cnt != (2 * mptReply->MsgLength)) {
4920 return -101;
4921 }
4922 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4923 return -102;
4924 }
4925#endif
4926
Prakash, Sathya436ace72007-07-24 15:42:08 +05304927 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004928 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004929
Prakash, Sathya436ace72007-07-24 15:42:08 +05304930 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931 ioc->name, t, u16cnt/2));
4932 return u16cnt/2;
4933}
4934
4935/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004936/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004937 * GetLanConfigPages - Fetch LANConfig pages.
4938 * @ioc: Pointer to MPT_ADAPTER structure
4939 *
4940 * Return: 0 for success
4941 * -ENOMEM if no memory available
4942 * -EPERM if not allowed due to ISR context
4943 * -EAGAIN if no msg frames currently available
4944 * -EFAULT for non-successful reply or no reply (timeout)
4945 */
4946static int
4947GetLanConfigPages(MPT_ADAPTER *ioc)
4948{
4949 ConfigPageHeader_t hdr;
4950 CONFIGPARMS cfg;
4951 LANPage0_t *ppage0_alloc;
4952 dma_addr_t page0_dma;
4953 LANPage1_t *ppage1_alloc;
4954 dma_addr_t page1_dma;
4955 int rc = 0;
4956 int data_sz;
4957 int copy_sz;
4958
4959 /* Get LAN Page 0 header */
4960 hdr.PageVersion = 0;
4961 hdr.PageLength = 0;
4962 hdr.PageNumber = 0;
4963 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004964 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965 cfg.physAddr = -1;
4966 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4967 cfg.dir = 0;
4968 cfg.pageAddr = 0;
4969 cfg.timeout = 0;
4970
4971 if ((rc = mpt_config(ioc, &cfg)) != 0)
4972 return rc;
4973
4974 if (hdr.PageLength > 0) {
4975 data_sz = hdr.PageLength * 4;
4976 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4977 rc = -ENOMEM;
4978 if (ppage0_alloc) {
4979 memset((u8 *)ppage0_alloc, 0, data_sz);
4980 cfg.physAddr = page0_dma;
4981 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4982
4983 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4984 /* save the data */
4985 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4986 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4987
4988 }
4989
4990 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4991
4992 /* FIXME!
4993 * Normalize endianness of structure data,
4994 * by byte-swapping all > 1 byte fields!
4995 */
4996
4997 }
4998
4999 if (rc)
5000 return rc;
5001 }
5002
5003 /* Get LAN Page 1 header */
5004 hdr.PageVersion = 0;
5005 hdr.PageLength = 0;
5006 hdr.PageNumber = 1;
5007 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005008 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005009 cfg.physAddr = -1;
5010 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5011 cfg.dir = 0;
5012 cfg.pageAddr = 0;
5013
5014 if ((rc = mpt_config(ioc, &cfg)) != 0)
5015 return rc;
5016
5017 if (hdr.PageLength == 0)
5018 return 0;
5019
5020 data_sz = hdr.PageLength * 4;
5021 rc = -ENOMEM;
5022 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
5023 if (ppage1_alloc) {
5024 memset((u8 *)ppage1_alloc, 0, data_sz);
5025 cfg.physAddr = page1_dma;
5026 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5027
5028 if ((rc = mpt_config(ioc, &cfg)) == 0) {
5029 /* save the data */
5030 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
5031 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
5032 }
5033
5034 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
5035
5036 /* FIXME!
5037 * Normalize endianness of structure data,
5038 * by byte-swapping all > 1 byte fields!
5039 */
5040
5041 }
5042
5043 return rc;
5044}
5045
5046/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005047/**
5048 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005049 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005050 * @persist_opcode: see below
5051 *
5052 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
5053 * devices not currently present.
5054 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
5055 *
5056 * NOTE: Don't use not this function during interrupt time.
5057 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005058 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005059 */
5060
5061/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5062int
5063mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
5064{
5065 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
5066 SasIoUnitControlReply_t *sasIoUnitCntrReply;
5067 MPT_FRAME_HDR *mf = NULL;
5068 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305069 int ret = 0;
5070 unsigned long timeleft;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005071
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305072 mutex_lock(&ioc->mptbase_cmds.mutex);
5073
5074 /* init the internal cmd struct */
5075 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
5076 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005077
5078 /* insure garbage is not sent to fw */
5079 switch(persist_opcode) {
5080
5081 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
5082 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
5083 break;
5084
5085 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305086 ret = -1;
5087 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005088 }
5089
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305090 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
5091 __func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005092
5093 /* Get a MF for this command.
5094 */
5095 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305096 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
5097 ret = -1;
5098 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005099 }
5100
5101 mpi_hdr = (MPIHeader_t *) mf;
5102 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
5103 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
5104 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
5105 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
5106 sasIoUnitCntrReq->Operation = persist_opcode;
5107
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005108 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305109 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
5110 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
5111 ret = -ETIME;
5112 printk(KERN_DEBUG "%s: failed\n", __func__);
5113 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
5114 goto out;
5115 if (!timeleft) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09005116 printk(MYIOC_s_WARN_FMT
5117 "Issuing Reset from %s!!, doorbell=0x%08x\n",
5118 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05305119 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305120 mpt_free_msg_frame(ioc, mf);
5121 }
5122 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005123 }
5124
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305125 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
5126 ret = -1;
5127 goto out;
5128 }
5129
5130 sasIoUnitCntrReply =
5131 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5132 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5133 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5134 __func__, sasIoUnitCntrReply->IOCStatus,
5135 sasIoUnitCntrReply->IOCLogInfo);
5136 printk(KERN_DEBUG "%s: failed\n", __func__);
5137 ret = -1;
5138 } else
5139 printk(KERN_DEBUG "%s: success\n", __func__);
5140 out:
5141
5142 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5143 mutex_unlock(&ioc->mptbase_cmds.mutex);
5144 return ret;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005145}
5146
5147/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005148
5149static void
5150mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5151 MpiEventDataRaid_t * pRaidEventData)
5152{
5153 int volume;
5154 int reason;
5155 int disk;
5156 int status;
5157 int flags;
5158 int state;
5159
5160 volume = pRaidEventData->VolumeID;
5161 reason = pRaidEventData->ReasonCode;
5162 disk = pRaidEventData->PhysDiskNum;
5163 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5164 flags = (status >> 0) & 0xff;
5165 state = (status >> 8) & 0xff;
5166
5167 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5168 return;
5169 }
5170
5171 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5172 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5173 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005174 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5175 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005176 } else {
5177 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5178 ioc->name, volume);
5179 }
5180
5181 switch(reason) {
5182 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5183 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5184 ioc->name);
5185 break;
5186
5187 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5188
5189 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5190 ioc->name);
5191 break;
5192
5193 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5194 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5195 ioc->name);
5196 break;
5197
5198 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5199 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5200 ioc->name,
5201 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5202 ? "optimal"
5203 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5204 ? "degraded"
5205 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5206 ? "failed"
5207 : "state unknown",
5208 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5209 ? ", enabled" : "",
5210 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5211 ? ", quiesced" : "",
5212 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5213 ? ", resync in progress" : "" );
5214 break;
5215
5216 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5217 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5218 ioc->name, disk);
5219 break;
5220
5221 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5222 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5223 ioc->name);
5224 break;
5225
5226 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5227 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5228 ioc->name);
5229 break;
5230
5231 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5232 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5233 ioc->name);
5234 break;
5235
5236 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5237 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5238 ioc->name,
5239 state == MPI_PHYSDISK0_STATUS_ONLINE
5240 ? "online"
5241 : state == MPI_PHYSDISK0_STATUS_MISSING
5242 ? "missing"
5243 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5244 ? "not compatible"
5245 : state == MPI_PHYSDISK0_STATUS_FAILED
5246 ? "failed"
5247 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5248 ? "initializing"
5249 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5250 ? "offline requested"
5251 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5252 ? "failed requested"
5253 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5254 ? "offline"
5255 : "state unknown",
5256 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5257 ? ", out of sync" : "",
5258 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5259 ? ", quiesced" : "" );
5260 break;
5261
5262 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5263 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5264 ioc->name, disk);
5265 break;
5266
5267 case MPI_EVENT_RAID_RC_SMART_DATA:
5268 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5269 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5270 break;
5271
5272 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5273 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5274 ioc->name, disk);
5275 break;
5276 }
5277}
5278
5279/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005280/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005281 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5282 * @ioc: Pointer to MPT_ADAPTER structure
5283 *
5284 * Returns: 0 for success
5285 * -ENOMEM if no memory available
5286 * -EPERM if not allowed due to ISR context
5287 * -EAGAIN if no msg frames currently available
5288 * -EFAULT for non-successful reply or no reply (timeout)
5289 */
5290static int
5291GetIoUnitPage2(MPT_ADAPTER *ioc)
5292{
5293 ConfigPageHeader_t hdr;
5294 CONFIGPARMS cfg;
5295 IOUnitPage2_t *ppage_alloc;
5296 dma_addr_t page_dma;
5297 int data_sz;
5298 int rc;
5299
5300 /* Get the page header */
5301 hdr.PageVersion = 0;
5302 hdr.PageLength = 0;
5303 hdr.PageNumber = 2;
5304 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005305 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005306 cfg.physAddr = -1;
5307 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5308 cfg.dir = 0;
5309 cfg.pageAddr = 0;
5310 cfg.timeout = 0;
5311
5312 if ((rc = mpt_config(ioc, &cfg)) != 0)
5313 return rc;
5314
5315 if (hdr.PageLength == 0)
5316 return 0;
5317
5318 /* Read the config page */
5319 data_sz = hdr.PageLength * 4;
5320 rc = -ENOMEM;
5321 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5322 if (ppage_alloc) {
5323 memset((u8 *)ppage_alloc, 0, data_sz);
5324 cfg.physAddr = page_dma;
5325 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5326
5327 /* If Good, save data */
5328 if ((rc = mpt_config(ioc, &cfg)) == 0)
5329 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5330
5331 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5332 }
5333
5334 return rc;
5335}
5336
5337/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005338/**
5339 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005340 * @ioc: Pointer to a Adapter Strucutre
5341 * @portnum: IOC port number
5342 *
5343 * Return: -EFAULT if read of config page header fails
5344 * or if no nvram
5345 * If read of SCSI Port Page 0 fails,
5346 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5347 * Adapter settings: async, narrow
5348 * Return 1
5349 * If read of SCSI Port Page 2 fails,
5350 * Adapter settings valid
5351 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5352 * Return 1
5353 * Else
5354 * Both valid
5355 * Return 0
5356 * CHECK - what type of locking mechanisms should be used????
5357 */
5358static int
5359mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5360{
5361 u8 *pbuf;
5362 dma_addr_t buf_dma;
5363 CONFIGPARMS cfg;
5364 ConfigPageHeader_t header;
5365 int ii;
5366 int data, rc = 0;
5367
5368 /* Allocate memory
5369 */
5370 if (!ioc->spi_data.nvram) {
5371 int sz;
5372 u8 *mem;
5373 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5374 mem = kmalloc(sz, GFP_ATOMIC);
5375 if (mem == NULL)
5376 return -EFAULT;
5377
5378 ioc->spi_data.nvram = (int *) mem;
5379
Prakash, Sathya436ace72007-07-24 15:42:08 +05305380 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381 ioc->name, ioc->spi_data.nvram, sz));
5382 }
5383
5384 /* Invalidate NVRAM information
5385 */
5386 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5387 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5388 }
5389
5390 /* Read SPP0 header, allocate memory, then read page.
5391 */
5392 header.PageVersion = 0;
5393 header.PageLength = 0;
5394 header.PageNumber = 0;
5395 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005396 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397 cfg.physAddr = -1;
5398 cfg.pageAddr = portnum;
5399 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5400 cfg.dir = 0;
5401 cfg.timeout = 0; /* use default */
5402 if (mpt_config(ioc, &cfg) != 0)
5403 return -EFAULT;
5404
5405 if (header.PageLength > 0) {
5406 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5407 if (pbuf) {
5408 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5409 cfg.physAddr = buf_dma;
5410 if (mpt_config(ioc, &cfg) != 0) {
5411 ioc->spi_data.maxBusWidth = MPT_NARROW;
5412 ioc->spi_data.maxSyncOffset = 0;
5413 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5414 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5415 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305416 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5417 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005418 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419 } else {
5420 /* Save the Port Page 0 data
5421 */
5422 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5423 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5424 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5425
5426 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5427 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005428 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5429 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005430 ioc->name, pPP0->Capabilities));
5431 }
5432 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5433 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5434 if (data) {
5435 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5436 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5437 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305438 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5439 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005440 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441 } else {
5442 ioc->spi_data.maxSyncOffset = 0;
5443 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5444 }
5445
5446 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5447
5448 /* Update the minSyncFactor based on bus type.
5449 */
5450 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5451 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5452
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005453 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305455 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5456 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005457 ioc->name, ioc->spi_data.minSyncFactor));
5458 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459 }
5460 }
5461 if (pbuf) {
5462 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5463 }
5464 }
5465 }
5466
5467 /* SCSI Port Page 2 - Read the header then the page.
5468 */
5469 header.PageVersion = 0;
5470 header.PageLength = 0;
5471 header.PageNumber = 2;
5472 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005473 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474 cfg.physAddr = -1;
5475 cfg.pageAddr = portnum;
5476 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5477 cfg.dir = 0;
5478 if (mpt_config(ioc, &cfg) != 0)
5479 return -EFAULT;
5480
5481 if (header.PageLength > 0) {
5482 /* Allocate memory and read SCSI Port Page 2
5483 */
5484 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5485 if (pbuf) {
5486 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5487 cfg.physAddr = buf_dma;
5488 if (mpt_config(ioc, &cfg) != 0) {
5489 /* Nvram data is left with INVALID mark
5490 */
5491 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005492 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5493
5494 /* This is an ATTO adapter, read Page2 accordingly
5495 */
5496 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5497 ATTODeviceInfo_t *pdevice = NULL;
5498 u16 ATTOFlags;
5499
5500 /* Save the Port Page 2 data
5501 * (reformat into a 32bit quantity)
5502 */
5503 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5504 pdevice = &pPP2->DeviceSettings[ii];
5505 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5506 data = 0;
5507
5508 /* Translate ATTO device flags to LSI format
5509 */
5510 if (ATTOFlags & ATTOFLAG_DISC)
5511 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5512 if (ATTOFlags & ATTOFLAG_ID_ENB)
5513 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5514 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5515 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5516 if (ATTOFlags & ATTOFLAG_TAGGED)
5517 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5518 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5519 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5520
5521 data = (data << 16) | (pdevice->Period << 8) | 10;
5522 ioc->spi_data.nvram[ii] = data;
5523 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524 } else {
5525 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5526 MpiDeviceInfo_t *pdevice = NULL;
5527
Moore, Ericd8e925d2006-01-16 18:53:06 -07005528 /*
5529 * Save "Set to Avoid SCSI Bus Resets" flag
5530 */
5531 ioc->spi_data.bus_reset =
5532 (le32_to_cpu(pPP2->PortFlags) &
5533 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5534 0 : 1 ;
5535
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 /* Save the Port Page 2 data
5537 * (reformat into a 32bit quantity)
5538 */
5539 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5540 ioc->spi_data.PortFlags = data;
5541 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5542 pdevice = &pPP2->DeviceSettings[ii];
5543 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5544 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5545 ioc->spi_data.nvram[ii] = data;
5546 }
5547 }
5548
5549 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5550 }
5551 }
5552
5553 /* Update Adapter limits with those from NVRAM
5554 * Comment: Don't need to do this. Target performance
5555 * parameters will never exceed the adapters limits.
5556 */
5557
5558 return rc;
5559}
5560
5561/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005562/**
5563 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005564 * @ioc: Pointer to a Adapter Strucutre
5565 * @portnum: IOC port number
5566 *
5567 * Return: -EFAULT if read of config page header fails
5568 * or 0 if success.
5569 */
5570static int
5571mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5572{
5573 CONFIGPARMS cfg;
5574 ConfigPageHeader_t header;
5575
5576 /* Read the SCSI Device Page 1 header
5577 */
5578 header.PageVersion = 0;
5579 header.PageLength = 0;
5580 header.PageNumber = 1;
5581 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005582 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 cfg.physAddr = -1;
5584 cfg.pageAddr = portnum;
5585 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5586 cfg.dir = 0;
5587 cfg.timeout = 0;
5588 if (mpt_config(ioc, &cfg) != 0)
5589 return -EFAULT;
5590
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005591 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5592 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005593
5594 header.PageVersion = 0;
5595 header.PageLength = 0;
5596 header.PageNumber = 0;
5597 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5598 if (mpt_config(ioc, &cfg) != 0)
5599 return -EFAULT;
5600
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005601 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5602 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603
Prakash, Sathya436ace72007-07-24 15:42:08 +05305604 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5606
Prakash, Sathya436ace72007-07-24 15:42:08 +05305607 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005608 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5609 return 0;
5610}
5611
Eric Mooreb506ade2007-01-29 09:45:37 -07005612/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005613 * mpt_inactive_raid_list_free - This clears this link list.
5614 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005615 **/
5616static void
5617mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5618{
5619 struct inactive_raid_component_info *component_info, *pNext;
5620
5621 if (list_empty(&ioc->raid_data.inactive_list))
5622 return;
5623
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005624 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005625 list_for_each_entry_safe(component_info, pNext,
5626 &ioc->raid_data.inactive_list, list) {
5627 list_del(&component_info->list);
5628 kfree(component_info);
5629 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005630 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005631}
5632
5633/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005634 * 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 -07005635 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005636 * @ioc : pointer to per adapter structure
5637 * @channel : volume channel
5638 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005639 **/
5640static void
5641mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5642{
5643 CONFIGPARMS cfg;
5644 ConfigPageHeader_t hdr;
5645 dma_addr_t dma_handle;
5646 pRaidVolumePage0_t buffer = NULL;
5647 int i;
5648 RaidPhysDiskPage0_t phys_disk;
5649 struct inactive_raid_component_info *component_info;
5650 int handle_inactive_volumes;
5651
5652 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5653 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5654 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5655 cfg.pageAddr = (channel << 8) + id;
5656 cfg.cfghdr.hdr = &hdr;
5657 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5658
5659 if (mpt_config(ioc, &cfg) != 0)
5660 goto out;
5661
5662 if (!hdr.PageLength)
5663 goto out;
5664
5665 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5666 &dma_handle);
5667
5668 if (!buffer)
5669 goto out;
5670
5671 cfg.physAddr = dma_handle;
5672 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5673
5674 if (mpt_config(ioc, &cfg) != 0)
5675 goto out;
5676
5677 if (!buffer->NumPhysDisks)
5678 goto out;
5679
5680 handle_inactive_volumes =
5681 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5682 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5683 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5684 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5685
5686 if (!handle_inactive_volumes)
5687 goto out;
5688
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005689 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005690 for (i = 0; i < buffer->NumPhysDisks; i++) {
5691 if(mpt_raid_phys_disk_pg0(ioc,
5692 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5693 continue;
5694
5695 if ((component_info = kmalloc(sizeof (*component_info),
5696 GFP_KERNEL)) == NULL)
5697 continue;
5698
5699 component_info->volumeID = id;
5700 component_info->volumeBus = channel;
5701 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5702 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5703 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5704 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5705
5706 list_add_tail(&component_info->list,
5707 &ioc->raid_data.inactive_list);
5708 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005709 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005710
5711 out:
5712 if (buffer)
5713 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5714 dma_handle);
5715}
5716
5717/**
5718 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5719 * @ioc: Pointer to a Adapter Structure
5720 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5721 * @phys_disk: requested payload data returned
5722 *
5723 * Return:
5724 * 0 on success
5725 * -EFAULT if read of config page header fails or data pointer not NULL
5726 * -ENOMEM if pci_alloc failed
5727 **/
5728int
Kashyap, Desai2f187862009-05-29 16:52:37 +05305729mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
5730 RaidPhysDiskPage0_t *phys_disk)
Eric Mooreb506ade2007-01-29 09:45:37 -07005731{
Kashyap, Desai2f187862009-05-29 16:52:37 +05305732 CONFIGPARMS cfg;
5733 ConfigPageHeader_t hdr;
Eric Mooreb506ade2007-01-29 09:45:37 -07005734 dma_addr_t dma_handle;
5735 pRaidPhysDiskPage0_t buffer = NULL;
5736 int rc;
5737
5738 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5739 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
Kashyap, Desai2f187862009-05-29 16:52:37 +05305740 memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
Eric Mooreb506ade2007-01-29 09:45:37 -07005741
Kashyap, Desai2f187862009-05-29 16:52:37 +05305742 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
Eric Mooreb506ade2007-01-29 09:45:37 -07005743 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5744 cfg.cfghdr.hdr = &hdr;
5745 cfg.physAddr = -1;
5746 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5747
5748 if (mpt_config(ioc, &cfg) != 0) {
5749 rc = -EFAULT;
5750 goto out;
5751 }
5752
5753 if (!hdr.PageLength) {
5754 rc = -EFAULT;
5755 goto out;
5756 }
5757
5758 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5759 &dma_handle);
5760
5761 if (!buffer) {
5762 rc = -ENOMEM;
5763 goto out;
5764 }
5765
5766 cfg.physAddr = dma_handle;
5767 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5768 cfg.pageAddr = phys_disk_num;
5769
5770 if (mpt_config(ioc, &cfg) != 0) {
5771 rc = -EFAULT;
5772 goto out;
5773 }
5774
5775 rc = 0;
5776 memcpy(phys_disk, buffer, sizeof(*buffer));
5777 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5778
5779 out:
5780
5781 if (buffer)
5782 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5783 dma_handle);
5784
5785 return rc;
5786}
5787
Linus Torvalds1da177e2005-04-16 15:20:36 -07005788/**
Kashyap, Desaia7938b02009-05-29 16:53:56 +05305789 * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
5790 * @ioc: Pointer to a Adapter Structure
5791 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5792 *
5793 * Return:
5794 * returns number paths
5795 **/
5796int
5797mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
5798{
5799 CONFIGPARMS cfg;
5800 ConfigPageHeader_t hdr;
5801 dma_addr_t dma_handle;
5802 pRaidPhysDiskPage1_t buffer = NULL;
5803 int rc;
5804
5805 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5806 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5807
5808 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5809 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5810 hdr.PageNumber = 1;
5811 cfg.cfghdr.hdr = &hdr;
5812 cfg.physAddr = -1;
5813 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5814
5815 if (mpt_config(ioc, &cfg) != 0) {
5816 rc = 0;
5817 goto out;
5818 }
5819
5820 if (!hdr.PageLength) {
5821 rc = 0;
5822 goto out;
5823 }
5824
5825 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5826 &dma_handle);
5827
5828 if (!buffer) {
5829 rc = 0;
5830 goto out;
5831 }
5832
5833 cfg.physAddr = dma_handle;
5834 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5835 cfg.pageAddr = phys_disk_num;
5836
5837 if (mpt_config(ioc, &cfg) != 0) {
5838 rc = 0;
5839 goto out;
5840 }
5841
5842 rc = buffer->NumPhysDiskPaths;
5843 out:
5844
5845 if (buffer)
5846 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5847 dma_handle);
5848
5849 return rc;
5850}
5851EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
5852
5853/**
5854 * mpt_raid_phys_disk_pg1 - returns phys disk page 1
5855 * @ioc: Pointer to a Adapter Structure
5856 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5857 * @phys_disk: requested payload data returned
5858 *
5859 * Return:
5860 * 0 on success
5861 * -EFAULT if read of config page header fails or data pointer not NULL
5862 * -ENOMEM if pci_alloc failed
5863 **/
5864int
5865mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
5866 RaidPhysDiskPage1_t *phys_disk)
5867{
5868 CONFIGPARMS cfg;
5869 ConfigPageHeader_t hdr;
5870 dma_addr_t dma_handle;
5871 pRaidPhysDiskPage1_t buffer = NULL;
5872 int rc;
5873 int i;
5874 __le64 sas_address;
5875
5876 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5877 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5878 rc = 0;
5879
5880 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5881 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5882 hdr.PageNumber = 1;
5883 cfg.cfghdr.hdr = &hdr;
5884 cfg.physAddr = -1;
5885 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5886
5887 if (mpt_config(ioc, &cfg) != 0) {
5888 rc = -EFAULT;
5889 goto out;
5890 }
5891
5892 if (!hdr.PageLength) {
5893 rc = -EFAULT;
5894 goto out;
5895 }
5896
5897 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5898 &dma_handle);
5899
5900 if (!buffer) {
5901 rc = -ENOMEM;
5902 goto out;
5903 }
5904
5905 cfg.physAddr = dma_handle;
5906 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5907 cfg.pageAddr = phys_disk_num;
5908
5909 if (mpt_config(ioc, &cfg) != 0) {
5910 rc = -EFAULT;
5911 goto out;
5912 }
5913
5914 phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
5915 phys_disk->PhysDiskNum = phys_disk_num;
5916 for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
5917 phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
5918 phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
5919 phys_disk->Path[i].OwnerIdentifier =
5920 buffer->Path[i].OwnerIdentifier;
5921 phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
5922 memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
5923 sas_address = le64_to_cpu(sas_address);
5924 memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
5925 memcpy(&sas_address,
5926 &buffer->Path[i].OwnerWWID, sizeof(__le64));
5927 sas_address = le64_to_cpu(sas_address);
5928 memcpy(&phys_disk->Path[i].OwnerWWID,
5929 &sas_address, sizeof(__le64));
5930 }
5931
5932 out:
5933
5934 if (buffer)
5935 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5936 dma_handle);
5937
5938 return rc;
5939}
5940EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
5941
5942
5943/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005944 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5945 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946 *
5947 * Return:
5948 * 0 on success
5949 * -EFAULT if read of config page header fails or data pointer not NULL
5950 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005951 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005952int
5953mpt_findImVolumes(MPT_ADAPTER *ioc)
5954{
5955 IOCPage2_t *pIoc2;
5956 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957 dma_addr_t ioc2_dma;
5958 CONFIGPARMS cfg;
5959 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960 int rc = 0;
5961 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005962 int i;
5963
5964 if (!ioc->ir_firmware)
5965 return 0;
5966
5967 /* Free the old page
5968 */
5969 kfree(ioc->raid_data.pIocPg2);
5970 ioc->raid_data.pIocPg2 = NULL;
5971 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005972
5973 /* Read IOCP2 header then the page.
5974 */
5975 header.PageVersion = 0;
5976 header.PageLength = 0;
5977 header.PageNumber = 2;
5978 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005979 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980 cfg.physAddr = -1;
5981 cfg.pageAddr = 0;
5982 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5983 cfg.dir = 0;
5984 cfg.timeout = 0;
5985 if (mpt_config(ioc, &cfg) != 0)
5986 return -EFAULT;
5987
5988 if (header.PageLength == 0)
5989 return -EFAULT;
5990
5991 iocpage2sz = header.PageLength * 4;
5992 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5993 if (!pIoc2)
5994 return -ENOMEM;
5995
5996 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5997 cfg.physAddr = ioc2_dma;
5998 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005999 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006000
Eric Mooreb506ade2007-01-29 09:45:37 -07006001 mem = kmalloc(iocpage2sz, GFP_KERNEL);
Julia Lawall1c1acab2010-08-11 12:11:24 +02006002 if (!mem) {
6003 rc = -ENOMEM;
Eric Mooreb506ade2007-01-29 09:45:37 -07006004 goto out;
Julia Lawall1c1acab2010-08-11 12:11:24 +02006005 }
Eric Mooreb506ade2007-01-29 09:45:37 -07006006
Linus Torvalds1da177e2005-04-16 15:20:36 -07006007 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07006008 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006009
Eric Mooreb506ade2007-01-29 09:45:37 -07006010 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006011
Eric Mooreb506ade2007-01-29 09:45:37 -07006012 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
6013 mpt_inactive_raid_volumes(ioc,
6014 pIoc2->RaidVolume[i].VolumeBus,
6015 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006016
Eric Mooreb506ade2007-01-29 09:45:37 -07006017 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006018 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
6019
6020 return rc;
6021}
6022
Moore, Ericc972c702006-03-14 09:14:06 -07006023static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07006024mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
6025{
6026 IOCPage3_t *pIoc3;
6027 u8 *mem;
6028 CONFIGPARMS cfg;
6029 ConfigPageHeader_t header;
6030 dma_addr_t ioc3_dma;
6031 int iocpage3sz = 0;
6032
6033 /* Free the old page
6034 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006035 kfree(ioc->raid_data.pIocPg3);
6036 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006037
6038 /* There is at least one physical disk.
6039 * Read and save IOC Page 3
6040 */
6041 header.PageVersion = 0;
6042 header.PageLength = 0;
6043 header.PageNumber = 3;
6044 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006045 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006046 cfg.physAddr = -1;
6047 cfg.pageAddr = 0;
6048 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6049 cfg.dir = 0;
6050 cfg.timeout = 0;
6051 if (mpt_config(ioc, &cfg) != 0)
6052 return 0;
6053
6054 if (header.PageLength == 0)
6055 return 0;
6056
6057 /* Read Header good, alloc memory
6058 */
6059 iocpage3sz = header.PageLength * 4;
6060 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
6061 if (!pIoc3)
6062 return 0;
6063
6064 /* Read the Page and save the data
6065 * into malloc'd memory.
6066 */
6067 cfg.physAddr = ioc3_dma;
6068 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6069 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07006070 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071 if (mem) {
6072 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006073 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006074 }
6075 }
6076
6077 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
6078
6079 return 0;
6080}
6081
6082static void
6083mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
6084{
6085 IOCPage4_t *pIoc4;
6086 CONFIGPARMS cfg;
6087 ConfigPageHeader_t header;
6088 dma_addr_t ioc4_dma;
6089 int iocpage4sz;
6090
6091 /* Read and save IOC Page 4
6092 */
6093 header.PageVersion = 0;
6094 header.PageLength = 0;
6095 header.PageNumber = 4;
6096 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006097 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006098 cfg.physAddr = -1;
6099 cfg.pageAddr = 0;
6100 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6101 cfg.dir = 0;
6102 cfg.timeout = 0;
6103 if (mpt_config(ioc, &cfg) != 0)
6104 return;
6105
6106 if (header.PageLength == 0)
6107 return;
6108
6109 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
6110 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
6111 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
6112 if (!pIoc4)
6113 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06006114 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006115 } else {
6116 ioc4_dma = ioc->spi_data.IocPg4_dma;
6117 iocpage4sz = ioc->spi_data.IocPg4Sz;
6118 }
6119
6120 /* Read the Page into dma memory.
6121 */
6122 cfg.physAddr = ioc4_dma;
6123 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6124 if (mpt_config(ioc, &cfg) == 0) {
6125 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
6126 ioc->spi_data.IocPg4_dma = ioc4_dma;
6127 ioc->spi_data.IocPg4Sz = iocpage4sz;
6128 } else {
6129 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
6130 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06006131 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006132 }
6133}
6134
6135static void
6136mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
6137{
6138 IOCPage1_t *pIoc1;
6139 CONFIGPARMS cfg;
6140 ConfigPageHeader_t header;
6141 dma_addr_t ioc1_dma;
6142 int iocpage1sz = 0;
6143 u32 tmp;
6144
6145 /* Check the Coalescing Timeout in IOC Page 1
6146 */
6147 header.PageVersion = 0;
6148 header.PageLength = 0;
6149 header.PageNumber = 1;
6150 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006151 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006152 cfg.physAddr = -1;
6153 cfg.pageAddr = 0;
6154 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6155 cfg.dir = 0;
6156 cfg.timeout = 0;
6157 if (mpt_config(ioc, &cfg) != 0)
6158 return;
6159
6160 if (header.PageLength == 0)
6161 return;
6162
6163 /* Read Header good, alloc memory
6164 */
6165 iocpage1sz = header.PageLength * 4;
6166 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
6167 if (!pIoc1)
6168 return;
6169
6170 /* Read the Page and check coalescing timeout
6171 */
6172 cfg.physAddr = ioc1_dma;
6173 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6174 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306175
Linus Torvalds1da177e2005-04-16 15:20:36 -07006176 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
6177 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
6178 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
6179
Prakash, Sathya436ace72007-07-24 15:42:08 +05306180 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006181 ioc->name, tmp));
6182
6183 if (tmp > MPT_COALESCING_TIMEOUT) {
6184 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
6185
6186 /* Write NVRAM and current
6187 */
6188 cfg.dir = 1;
6189 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
6190 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306191 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006192 ioc->name, MPT_COALESCING_TIMEOUT));
6193
6194 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
6195 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306196 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6197 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006198 ioc->name, MPT_COALESCING_TIMEOUT));
6199 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306200 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6201 "Reset NVRAM Coalescing Timeout Failed\n",
6202 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006203 }
6204
6205 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306206 dprintk(ioc, printk(MYIOC_s_WARN_FMT
6207 "Reset of Current Coalescing Timeout Failed!\n",
6208 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006209 }
6210 }
6211
6212 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306213 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006214 }
6215 }
6216
6217 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
6218
6219 return;
6220}
6221
Prakash, Sathyaedb90682007-07-17 14:39:14 +05306222static void
6223mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
6224{
6225 CONFIGPARMS cfg;
6226 ConfigPageHeader_t hdr;
6227 dma_addr_t buf_dma;
6228 ManufacturingPage0_t *pbuf = NULL;
6229
6230 memset(&cfg, 0 , sizeof(CONFIGPARMS));
6231 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
6232
6233 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
6234 cfg.cfghdr.hdr = &hdr;
6235 cfg.physAddr = -1;
6236 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6237 cfg.timeout = 10;
6238
6239 if (mpt_config(ioc, &cfg) != 0)
6240 goto out;
6241
6242 if (!cfg.cfghdr.hdr->PageLength)
6243 goto out;
6244
6245 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6246 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
6247 if (!pbuf)
6248 goto out;
6249
6250 cfg.physAddr = buf_dma;
6251
6252 if (mpt_config(ioc, &cfg) != 0)
6253 goto out;
6254
6255 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
6256 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
6257 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
6258
Ewan D. Milnee8c61ec2016-02-23 09:00:12 -05006259out:
Prakash, Sathyaedb90682007-07-17 14:39:14 +05306260
6261 if (pbuf)
6262 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
6263}
6264
Linus Torvalds1da177e2005-04-16 15:20:36 -07006265/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006266/**
6267 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006268 * @ioc: Pointer to MPT_ADAPTER structure
6269 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05306270 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07006271 */
6272static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05306273SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274{
Kashyap, Desaifd761752009-05-29 16:39:06 +05306275 EventNotification_t evn;
6276 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006277
Kashyap, Desaifd761752009-05-29 16:39:06 +05306278 memset(&evn, 0, sizeof(EventNotification_t));
6279 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006280
Kashyap, Desaifd761752009-05-29 16:39:06 +05306281 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
6282 evn.Switch = EvSwitch;
6283 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006284
Kashyap, Desaifd761752009-05-29 16:39:06 +05306285 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6286 "Sending EventNotification (%d) request %p\n",
6287 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006288
Kashyap, Desaifd761752009-05-29 16:39:06 +05306289 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6290 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6291 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006292}
6293
6294/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6295/**
6296 * SendEventAck - Send EventAck request to MPT adapter.
6297 * @ioc: Pointer to MPT_ADAPTER structure
6298 * @evnp: Pointer to original EventNotification request
6299 */
6300static int
6301SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6302{
6303 EventAck_t *pAck;
6304
6305 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306306 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306307 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006308 return -1;
6309 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006310
Prakash, Sathya436ace72007-07-24 15:42:08 +05306311 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006312
6313 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6314 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006315 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006316 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006317 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006318 pAck->Event = evnp->Event;
6319 pAck->EventContext = evnp->EventContext;
6320
6321 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6322
6323 return 0;
6324}
6325
6326/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6327/**
6328 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006329 * @ioc: Pointer to an adapter structure
6330 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006331 * action, page address, direction, physical address
6332 * and pointer to a configuration page header
6333 * Page header is updated.
6334 *
6335 * Returns 0 for success
6336 * -EPERM if not allowed due to ISR context
6337 * -EAGAIN if no msg frames currently available
6338 * -EFAULT for non-successful reply or no reply (timeout)
6339 */
6340int
6341mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6342{
6343 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306344 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006345 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006346 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306347 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006348 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306349 long timeout;
6350 int ret;
6351 u8 page_type = 0, extend_page;
6352 unsigned long timeleft;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306353 unsigned long flags;
6354 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306355 u8 issue_hard_reset = 0;
6356 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006357
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006358 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006359 * to be in ISR context, because that is fatal!
6360 */
6361 in_isr = in_interrupt();
6362 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306363 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006364 ioc->name));
6365 return -EPERM;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306366 }
6367
6368 /* don't send a config page during diag reset */
6369 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6370 if (ioc->ioc_reset_in_progress) {
6371 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6372 "%s: busy with host reset\n", ioc->name, __func__));
6373 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6374 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006375 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306376 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006377
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306378 /* don't send if no chance of success */
6379 if (!ioc->active ||
6380 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6381 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6382 "%s: ioc not operational, %d, %xh\n",
6383 ioc->name, __func__, ioc->active,
6384 mpt_GetIocState(ioc, 0)));
6385 return -EFAULT;
6386 }
6387
6388 retry_config:
6389 mutex_lock(&ioc->mptbase_cmds.mutex);
6390 /* init the internal cmd struct */
6391 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6392 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6393
Linus Torvalds1da177e2005-04-16 15:20:36 -07006394 /* Get and Populate a free Frame
6395 */
6396 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306397 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6398 "mpt_config: no msg frames!\n", ioc->name));
6399 ret = -EAGAIN;
6400 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006401 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306402
Linus Torvalds1da177e2005-04-16 15:20:36 -07006403 pReq = (Config_t *)mf;
6404 pReq->Action = pCfg->action;
6405 pReq->Reserved = 0;
6406 pReq->ChainOffset = 0;
6407 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006408
6409 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006410 pReq->ExtPageLength = 0;
6411 pReq->ExtPageType = 0;
6412 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006413
Linus Torvalds1da177e2005-04-16 15:20:36 -07006414 for (ii=0; ii < 8; ii++)
6415 pReq->Reserved2[ii] = 0;
6416
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006417 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6418 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6419 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6420 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6421
6422 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6423 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6424 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6425 pReq->ExtPageType = pExtHdr->ExtPageType;
6426 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6427
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306428 /* Page Length must be treated as a reserved field for the
6429 * extended header.
6430 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006431 pReq->Header.PageLength = 0;
6432 }
6433
Linus Torvalds1da177e2005-04-16 15:20:36 -07006434 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6435
6436 /* Add a SGE to the config request.
6437 */
6438 if (pCfg->dir)
6439 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6440 else
6441 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6442
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306443 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6444 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006445 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306446 page_type = pReq->ExtPageType;
6447 extend_page = 1;
6448 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006449 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306450 page_type = pReq->Header.PageType;
6451 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006452 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006453
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306454 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6455 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6456 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6457
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306458 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306459 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006460 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306461 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6462 timeout);
6463 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6464 ret = -ETIME;
6465 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6466 "Failed Sending Config request type 0x%x, page 0x%x,"
6467 " action %d, status %xh, time left %ld\n\n",
6468 ioc->name, page_type, pReq->Header.PageNumber,
6469 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6470 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6471 goto out;
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05306472 if (!timeleft) {
6473 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6474 if (ioc->ioc_reset_in_progress) {
6475 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
6476 flags);
6477 printk(MYIOC_s_INFO_FMT "%s: host reset in"
6478 " progress mpt_config timed out.!!\n",
6479 __func__, ioc->name);
Dan Carpenter83ff74e2011-08-27 12:59:30 +03006480 mutex_unlock(&ioc->mptbase_cmds.mutex);
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05306481 return -EFAULT;
6482 }
6483 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306484 issue_hard_reset = 1;
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05306485 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306486 goto out;
6487 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006488
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306489 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6490 ret = -1;
6491 goto out;
6492 }
6493 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6494 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6495 if (ret == MPI_IOCSTATUS_SUCCESS) {
6496 if (extend_page) {
6497 pCfg->cfghdr.ehdr->ExtPageLength =
6498 le16_to_cpu(pReply->ExtPageLength);
6499 pCfg->cfghdr.ehdr->ExtPageType =
6500 pReply->ExtPageType;
6501 }
6502 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6503 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6504 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6505 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006506
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306507 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006508
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306509 if (retry_count)
6510 printk(MYIOC_s_INFO_FMT "Retry completed "
6511 "ret=0x%x timeleft=%ld\n",
6512 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006513
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306514 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6515 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006516
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306517out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006518
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306519 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6520 mutex_unlock(&ioc->mptbase_cmds.mutex);
6521 if (issue_hard_reset) {
6522 issue_hard_reset = 0;
Kei Tokunaga97009a22010-06-22 19:01:51 +09006523 printk(MYIOC_s_WARN_FMT
6524 "Issuing Reset from %s!!, doorbell=0x%08x\n",
6525 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaib3b97312010-03-18 19:14:51 +05306526 if (retry_count == 0) {
6527 if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0)
6528 retry_count++;
6529 } else
6530 mpt_HardResetHandler(ioc, CAN_SLEEP);
6531
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306532 mpt_free_msg_frame(ioc, mf);
6533 /* attempt one retry for a timed out command */
Kashyap, Desaib3b97312010-03-18 19:14:51 +05306534 if (retry_count < 2) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306535 printk(MYIOC_s_INFO_FMT
6536 "Attempting Retry Config request"
6537 " type 0x%x, page 0x%x,"
6538 " action %d\n", ioc->name, page_type,
6539 pCfg->cfghdr.hdr->PageNumber, pCfg->action);
6540 retry_count++;
6541 goto retry_config;
6542 }
6543 }
6544 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006545
Linus Torvalds1da177e2005-04-16 15:20:36 -07006546}
6547
6548/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006549/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006550 * mpt_ioc_reset - Base cleanup for hard reset
6551 * @ioc: Pointer to the adapter structure
6552 * @reset_phase: Indicates pre- or post-reset functionality
6553 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006554 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006555 */
6556static int
6557mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6558{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306559 switch (reset_phase) {
6560 case MPT_IOC_SETUP_RESET:
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306561 ioc->taskmgmt_quiesce_io = 1;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306562 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6563 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
6564 break;
6565 case MPT_IOC_PRE_RESET:
6566 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6567 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
6568 break;
6569 case MPT_IOC_POST_RESET:
6570 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6571 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
6572/* wake up mptbase_cmds */
6573 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6574 ioc->mptbase_cmds.status |=
6575 MPT_MGMT_STATUS_DID_IOCRESET;
6576 complete(&ioc->mptbase_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006577 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306578/* wake up taskmgmt_cmds */
6579 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
6580 ioc->taskmgmt_cmds.status |=
6581 MPT_MGMT_STATUS_DID_IOCRESET;
6582 complete(&ioc->taskmgmt_cmds.done);
6583 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306584 break;
6585 default:
6586 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006587 }
6588
6589 return 1; /* currently means nothing really */
6590}
6591
6592
6593#ifdef CONFIG_PROC_FS /* { */
6594/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6595/*
6596 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6597 */
6598/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006599/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006600 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6601 *
6602 * Returns 0 for success, non-zero for failure.
6603 */
6604static int
6605procmpt_create(void)
6606{
Linus Torvalds1da177e2005-04-16 15:20:36 -07006607 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6608 if (mpt_proc_root_dir == NULL)
6609 return -ENOTDIR;
6610
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006611 proc_create("summary", S_IRUGO, mpt_proc_root_dir, &mpt_summary_proc_fops);
6612 proc_create("version", S_IRUGO, mpt_proc_root_dir, &mpt_version_proc_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006613 return 0;
6614}
6615
6616/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006617/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006618 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6619 *
6620 * Returns 0 for success, non-zero for failure.
6621 */
6622static void
6623procmpt_destroy(void)
6624{
6625 remove_proc_entry("version", mpt_proc_root_dir);
6626 remove_proc_entry("summary", mpt_proc_root_dir);
6627 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6628}
6629
6630/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlap1f5cfe22010-08-14 13:05:50 -07006631/*
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006632 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006633 */
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006634static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan);
6635
6636static int mpt_summary_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006637{
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006638 MPT_ADAPTER *ioc = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006639
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006640 if (ioc) {
6641 seq_mpt_print_ioc_summary(ioc, m, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006642 } else {
6643 list_for_each_entry(ioc, &ioc_list, list) {
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006644 seq_mpt_print_ioc_summary(ioc, m, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006645 }
6646 }
6647
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006648 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006649}
6650
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006651static int mpt_summary_proc_open(struct inode *inode, struct file *file)
6652{
Al Virod9dda782013-03-31 18:16:14 -04006653 return single_open(file, mpt_summary_proc_show, PDE_DATA(inode));
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006654}
6655
6656static const struct file_operations mpt_summary_proc_fops = {
6657 .owner = THIS_MODULE,
6658 .open = mpt_summary_proc_open,
6659 .read = seq_read,
6660 .llseek = seq_lseek,
6661 .release = single_release,
6662};
6663
6664static int mpt_version_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006665{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306666 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006667 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006668 char *drvname;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006669
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006670 seq_printf(m, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6671 seq_printf(m, " Fusion MPT base driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006672
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006673 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006674 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006675 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306676 if (MptCallbacks[cb_idx]) {
6677 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006678 case MPTSPI_DRIVER:
6679 if (!scsi++) drvname = "SPI host";
6680 break;
6681 case MPTFC_DRIVER:
6682 if (!fc++) drvname = "FC host";
6683 break;
6684 case MPTSAS_DRIVER:
6685 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006686 break;
6687 case MPTLAN_DRIVER:
6688 if (!lan++) drvname = "LAN";
6689 break;
6690 case MPTSTM_DRIVER:
6691 if (!targ++) drvname = "SCSI target";
6692 break;
6693 case MPTCTL_DRIVER:
6694 if (!ctl++) drvname = "ioctl";
6695 break;
6696 }
6697
6698 if (drvname)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006699 seq_printf(m, " Fusion MPT %s driver\n", drvname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006700 }
6701 }
6702
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006703 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006704}
6705
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006706static int mpt_version_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006707{
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006708 return single_open(file, mpt_version_proc_show, NULL);
6709}
6710
6711static const struct file_operations mpt_version_proc_fops = {
6712 .owner = THIS_MODULE,
6713 .open = mpt_version_proc_open,
6714 .read = seq_read,
6715 .llseek = seq_lseek,
6716 .release = single_release,
6717};
6718
6719static int mpt_iocinfo_proc_show(struct seq_file *m, void *v)
6720{
6721 MPT_ADAPTER *ioc = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006722 char expVer[32];
6723 int sz;
6724 int p;
6725
6726 mpt_get_fw_exp_ver(expVer, ioc);
6727
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006728 seq_printf(m, "%s:", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006729 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006730 seq_printf(m, " (f/w download boot flag set)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006731// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006732// seq_printf(m, " CONFIG_CHECKSUM_FAIL!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006733
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006734 seq_printf(m, "\n ProductID = 0x%04x (%s)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006735 ioc->facts.ProductID,
6736 ioc->prod_name);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006737 seq_printf(m, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006738 if (ioc->facts.FWImageSize)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006739 seq_printf(m, " (fw_size=%d)", ioc->facts.FWImageSize);
6740 seq_printf(m, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6741 seq_printf(m, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6742 seq_printf(m, " EventState = 0x%02x\n", ioc->facts.EventState);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006743
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006744 seq_printf(m, " CurrentHostMfaHighAddr = 0x%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006745 ioc->facts.CurrentHostMfaHighAddr);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006746 seq_printf(m, " CurrentSenseBufferHighAddr = 0x%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006747 ioc->facts.CurrentSenseBufferHighAddr);
6748
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006749 seq_printf(m, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6750 seq_printf(m, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006751
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006752 seq_printf(m, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006753 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6754 /*
6755 * Rounding UP to nearest 4-kB boundary here...
6756 */
6757 sz = (ioc->req_sz * ioc->req_depth) + 128;
6758 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006759 seq_printf(m, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006760 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006761 seq_printf(m, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006762 4*ioc->facts.RequestFrameSize,
6763 ioc->facts.GlobalCredits);
6764
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006765 seq_printf(m, " Frames @ 0x%p (Dma @ 0x%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006766 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6767 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006768 seq_printf(m, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006769 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006770 seq_printf(m, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006771 ioc->facts.CurReplyFrameSize,
6772 ioc->facts.ReplyQueueDepth);
6773
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006774 seq_printf(m, " MaxDevices = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006775 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006776 seq_printf(m, " MaxBuses = %d\n", ioc->facts.MaxBuses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006777
6778 /* per-port info */
6779 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006780 seq_printf(m, " PortNumber = %d (of %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006781 p+1,
6782 ioc->facts.NumberOfPorts);
6783 if (ioc->bus_type == FC) {
6784 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6785 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006786 seq_printf(m, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006787 a[5], a[4], a[3], a[2], a[1], a[0]);
6788 }
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006789 seq_printf(m, " WWN = %08X%08X:%08X%08X\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006790 ioc->fc_port_page0[p].WWNN.High,
6791 ioc->fc_port_page0[p].WWNN.Low,
6792 ioc->fc_port_page0[p].WWPN.High,
6793 ioc->fc_port_page0[p].WWPN.Low);
6794 }
6795 }
6796
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006797 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006798}
6799
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006800static int mpt_iocinfo_proc_open(struct inode *inode, struct file *file)
6801{
Al Virod9dda782013-03-31 18:16:14 -04006802 return single_open(file, mpt_iocinfo_proc_show, PDE_DATA(inode));
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006803}
6804
6805static const struct file_operations mpt_iocinfo_proc_fops = {
6806 .owner = THIS_MODULE,
6807 .open = mpt_iocinfo_proc_open,
6808 .read = seq_read,
6809 .llseek = seq_lseek,
6810 .release = single_release,
6811};
Linus Torvalds1da177e2005-04-16 15:20:36 -07006812#endif /* CONFIG_PROC_FS } */
6813
6814/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6815static void
6816mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6817{
6818 buf[0] ='\0';
6819 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6820 sprintf(buf, " (Exp %02d%02d)",
6821 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6822 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6823
6824 /* insider hack! */
6825 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6826 strcat(buf, " [MDBG]");
6827 }
6828}
6829
6830/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6831/**
6832 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6833 * @ioc: Pointer to MPT_ADAPTER structure
6834 * @buffer: Pointer to buffer where IOC summary info should be written
6835 * @size: Pointer to number of bytes we wrote (set by this routine)
6836 * @len: Offset at which to start writing in buffer
6837 * @showlan: Display LAN stuff?
6838 *
6839 * This routine writes (english readable) ASCII text, which represents
6840 * a summary of IOC information, to a buffer.
6841 */
6842void
6843mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6844{
6845 char expVer[32];
6846 int y;
6847
6848 mpt_get_fw_exp_ver(expVer, ioc);
6849
6850 /*
6851 * Shorter summary of attached ioc's...
6852 */
6853 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6854 ioc->name,
6855 ioc->prod_name,
6856 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6857 ioc->facts.FWVersion.Word,
6858 expVer,
6859 ioc->facts.NumberOfPorts,
6860 ioc->req_depth);
6861
6862 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6863 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6864 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6865 a[5], a[4], a[3], a[2], a[1], a[0]);
6866 }
6867
Linus Torvalds1da177e2005-04-16 15:20:36 -07006868 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006869
6870 if (!ioc->active)
6871 y += sprintf(buffer+len+y, " (disabled)");
6872
6873 y += sprintf(buffer+len+y, "\n");
6874
6875 *size = y;
6876}
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006877
Arnd Bergmann28558f52016-01-27 16:57:18 +01006878#ifdef CONFIG_PROC_FS
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006879static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan)
6880{
6881 char expVer[32];
6882
6883 mpt_get_fw_exp_ver(expVer, ioc);
6884
6885 /*
6886 * Shorter summary of attached ioc's...
6887 */
6888 seq_printf(m, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6889 ioc->name,
6890 ioc->prod_name,
6891 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6892 ioc->facts.FWVersion.Word,
6893 expVer,
6894 ioc->facts.NumberOfPorts,
6895 ioc->req_depth);
6896
6897 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6898 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6899 seq_printf(m, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6900 a[5], a[4], a[3], a[2], a[1], a[0]);
6901 }
6902
6903 seq_printf(m, ", IRQ=%d", ioc->pci_irq);
6904
6905 if (!ioc->active)
6906 seq_printf(m, " (disabled)");
6907
6908 seq_putc(m, '\n');
6909}
Arnd Bergmann28558f52016-01-27 16:57:18 +01006910#endif
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006911
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306912/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006913 * mpt_set_taskmgmt_in_progress_flag - set flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306914 * @ioc: Pointer to MPT_ADAPTER structure
6915 *
6916 * Returns 0 for SUCCESS or -1 if FAILED.
6917 *
6918 * If -1 is return, then it was not possible to set the flags
6919 **/
6920int
6921mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6922{
6923 unsigned long flags;
6924 int retval;
6925
6926 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6927 if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
6928 (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
6929 retval = -1;
6930 goto out;
6931 }
6932 retval = 0;
6933 ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306934 ioc->taskmgmt_quiesce_io = 1;
6935 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306936 ioc->alt_ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306937 ioc->alt_ioc->taskmgmt_quiesce_io = 1;
6938 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306939 out:
6940 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6941 return retval;
6942}
6943EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
6944
6945/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006946 * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306947 * @ioc: Pointer to MPT_ADAPTER structure
6948 *
6949 **/
6950void
6951mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6952{
6953 unsigned long flags;
6954
6955 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6956 ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306957 ioc->taskmgmt_quiesce_io = 0;
6958 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306959 ioc->alt_ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306960 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
6961 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306962 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6963}
6964EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006965
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306966
6967/**
6968 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6969 * the kernel
6970 * @ioc: Pointer to MPT_ADAPTER structure
6971 *
6972 **/
6973void
6974mpt_halt_firmware(MPT_ADAPTER *ioc)
6975{
6976 u32 ioc_raw_state;
6977
6978 ioc_raw_state = mpt_GetIocState(ioc, 0);
6979
6980 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6981 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6982 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6983 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6984 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6985 } else {
6986 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6987 panic("%s: Firmware is halted due to command timeout\n",
6988 ioc->name);
6989 }
6990}
6991EXPORT_SYMBOL(mpt_halt_firmware);
6992
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306993/**
6994 * mpt_SoftResetHandler - Issues a less expensive reset
6995 * @ioc: Pointer to MPT_ADAPTER structure
6996 * @sleepFlag: Indicates if sleep or schedule must be called.
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306997 *
6998 * Returns 0 for SUCCESS or -1 if FAILED.
6999 *
7000 * Message Unit Reset - instructs the IOC to reset the Reply Post and
7001 * Free FIFO's. All the Message Frames on Reply Free FIFO are discarded.
7002 * All posted buffers are freed, and event notification is turned off.
Lucas De Marchi25985ed2011-03-30 22:57:33 -03007003 * IOC doesn't reply to any outstanding request. This will transfer IOC
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05307004 * to READY state.
7005 **/
Joe Lawrence5767d252014-06-25 17:05:49 -04007006static int
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05307007mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
7008{
7009 int rc;
7010 int ii;
7011 u8 cb_idx;
7012 unsigned long flags;
7013 u32 ioc_state;
7014 unsigned long time_count;
7015
7016 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n",
7017 ioc->name));
7018
7019 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
7020
7021 if (mpt_fwfault_debug)
7022 mpt_halt_firmware(ioc);
7023
7024 if (ioc_state == MPI_IOC_STATE_FAULT ||
7025 ioc_state == MPI_IOC_STATE_RESET) {
7026 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7027 "skipping, either in FAULT or RESET state!\n", ioc->name));
7028 return -1;
7029 }
7030
7031 if (ioc->bus_type == FC) {
7032 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7033 "skipping, because the bus type is FC!\n", ioc->name));
7034 return -1;
7035 }
7036
7037 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7038 if (ioc->ioc_reset_in_progress) {
7039 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7040 return -1;
7041 }
7042 ioc->ioc_reset_in_progress = 1;
7043 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7044
7045 rc = -1;
7046
7047 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7048 if (MptResetHandlers[cb_idx])
7049 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
7050 }
7051
7052 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7053 if (ioc->taskmgmt_in_progress) {
Kashyap, Desaib9a0f872010-06-17 14:42:39 +05307054 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05307055 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7056 return -1;
7057 }
7058 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7059 /* Disable reply interrupts (also blocks FreeQ) */
7060 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
7061 ioc->active = 0;
7062 time_count = jiffies;
7063
7064 rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
7065
7066 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7067 if (MptResetHandlers[cb_idx])
7068 mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
7069 }
7070
7071 if (rc)
7072 goto out;
7073
7074 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
7075 if (ioc_state != MPI_IOC_STATE_READY)
7076 goto out;
7077
7078 for (ii = 0; ii < 5; ii++) {
7079 /* Get IOC facts! Allow 5 retries */
7080 rc = GetIocFacts(ioc, sleepFlag,
7081 MPT_HOSTEVENT_IOC_RECOVER);
7082 if (rc == 0)
7083 break;
7084 if (sleepFlag == CAN_SLEEP)
7085 msleep(100);
7086 else
7087 mdelay(100);
7088 }
7089 if (ii == 5)
7090 goto out;
7091
7092 rc = PrimeIocFifos(ioc);
7093 if (rc != 0)
7094 goto out;
7095
7096 rc = SendIocInit(ioc, sleepFlag);
7097 if (rc != 0)
7098 goto out;
7099
7100 rc = SendEventNotification(ioc, 1, sleepFlag);
7101 if (rc != 0)
7102 goto out;
7103
7104 if (ioc->hard_resets < -1)
7105 ioc->hard_resets++;
7106
7107 /*
7108 * At this point, we know soft reset succeeded.
7109 */
7110
7111 ioc->active = 1;
7112 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
7113
7114 out:
7115 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7116 ioc->ioc_reset_in_progress = 0;
7117 ioc->taskmgmt_quiesce_io = 0;
7118 ioc->taskmgmt_in_progress = 0;
7119 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7120
7121 if (ioc->active) { /* otherwise, hard reset coming */
7122 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7123 if (MptResetHandlers[cb_idx])
7124 mpt_signal_reset(cb_idx, ioc,
7125 MPT_IOC_POST_RESET);
7126 }
7127 }
7128
7129 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7130 "SoftResetHandler: completed (%d seconds): %s\n",
7131 ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,
7132 ((rc == 0) ? "SUCCESS" : "FAILED")));
7133
7134 return rc;
7135}
7136
7137/**
7138 * mpt_Soft_Hard_ResetHandler - Try less expensive reset
7139 * @ioc: Pointer to MPT_ADAPTER structure
7140 * @sleepFlag: Indicates if sleep or schedule must be called.
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05307141 *
7142 * Returns 0 for SUCCESS or -1 if FAILED.
7143 * Try for softreset first, only if it fails go for expensive
7144 * HardReset.
7145 **/
7146int
7147mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag) {
7148 int ret = -1;
7149
7150 ret = mpt_SoftResetHandler(ioc, sleepFlag);
7151 if (ret == 0)
7152 return ret;
7153 ret = mpt_HardResetHandler(ioc, sleepFlag);
7154 return ret;
7155}
7156EXPORT_SYMBOL(mpt_Soft_Hard_ResetHandler);
7157
Linus Torvalds1da177e2005-04-16 15:20:36 -07007158/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7159/*
7160 * Reset Handling
7161 */
7162/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7163/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007164 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07007165 * @ioc: Pointer to MPT_ADAPTER structure
7166 * @sleepFlag: Indicates if sleep or schedule must be called.
7167 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007168 * Issues SCSI Task Management call based on input arg values.
7169 * If TaskMgmt fails, returns associated SCSI request.
7170 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07007171 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
7172 * or a non-interrupt thread. In the former, must not call schedule().
7173 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007174 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07007175 * FW reload/initialization failed.
7176 *
7177 * Returns 0 for SUCCESS or -1 if FAILED.
7178 */
7179int
7180mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
7181{
Kashyap, Desaid1306912009-08-05 12:53:51 +05307182 int rc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307183 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007184 unsigned long flags;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307185 unsigned long time_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007186
Prakash, Sathya436ace72007-07-24 15:42:08 +05307187 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007188#ifdef MFCNT
7189 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
7190 printk("MF count 0x%x !\n", ioc->mfcnt);
7191#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05307192 if (mpt_fwfault_debug)
7193 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007194
7195 /* Reset the adapter. Prevent more than 1 call to
7196 * mpt_do_ioc_recovery at any instant in time.
7197 */
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307198 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7199 if (ioc->ioc_reset_in_progress) {
7200 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05307201 ioc->wait_on_reset_completion = 1;
7202 do {
7203 ssleep(1);
7204 } while (ioc->ioc_reset_in_progress == 1);
7205 ioc->wait_on_reset_completion = 0;
7206 return ioc->reset_status;
7207 }
7208 if (ioc->wait_on_reset_completion) {
7209 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7210 rc = 0;
7211 time_count = jiffies;
7212 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007213 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307214 ioc->ioc_reset_in_progress = 1;
7215 if (ioc->alt_ioc)
7216 ioc->alt_ioc->ioc_reset_in_progress = 1;
7217 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007218
Linus Torvalds1da177e2005-04-16 15:20:36 -07007219
7220 /* The SCSI driver needs to adjust timeouts on all current
7221 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02007222 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007223 * For all other protocol drivers, this is a no-op.
7224 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05307225 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7226 if (MptResetHandlers[cb_idx]) {
7227 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
7228 if (ioc->alt_ioc)
7229 mpt_signal_reset(cb_idx, ioc->alt_ioc,
7230 MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007231 }
7232 }
7233
Kashyap, Desai2f187862009-05-29 16:52:37 +05307234 time_count = jiffies;
7235 rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
7236 if (rc != 0) {
7237 printk(KERN_WARNING MYNAM
Kei Tokunaga97009a22010-06-22 19:01:51 +09007238 ": WARNING - (%d) Cannot recover %s, doorbell=0x%08x\n",
7239 rc, ioc->name, mpt_GetIocState(ioc, 0));
Kashyap, Desai2f187862009-05-29 16:52:37 +05307240 } else {
7241 if (ioc->hard_resets < -1)
7242 ioc->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007243 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007244
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307245 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7246 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307247 ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307248 ioc->taskmgmt_in_progress = 0;
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05307249 ioc->reset_status = rc;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307250 if (ioc->alt_ioc) {
7251 ioc->alt_ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307252 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307253 ioc->alt_ioc->taskmgmt_in_progress = 0;
7254 }
7255 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007256
Kashyap, Desaid1306912009-08-05 12:53:51 +05307257 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7258 if (MptResetHandlers[cb_idx]) {
7259 mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
7260 if (ioc->alt_ioc)
7261 mpt_signal_reset(cb_idx,
7262 ioc->alt_ioc, MPT_IOC_POST_RESET);
7263 }
7264 }
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05307265exit:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307266 dtmprintk(ioc,
7267 printk(MYIOC_s_DEBUG_FMT
7268 "HardResetHandler: completed (%d seconds): %s\n", ioc->name,
7269 jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?
7270 "SUCCESS" : "FAILED")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007271
7272 return rc;
7273}
7274
Kashyap, Desai2f187862009-05-29 16:52:37 +05307275#ifdef CONFIG_FUSION_LOGGING
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007276static void
Kashyap, Desai2f187862009-05-29 16:52:37 +05307277mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007278{
Eric Moore509e5e52006-04-26 13:22:37 -06007279 char *ds = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307280 u32 evData0;
7281 int ii;
7282 u8 event;
7283 char *evStr = ioc->evStr;
7284
7285 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7286 evData0 = le32_to_cpu(pEventReply->Data[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007287
7288 switch(event) {
7289 case MPI_EVENT_NONE:
7290 ds = "None";
7291 break;
7292 case MPI_EVENT_LOG_DATA:
7293 ds = "Log Data";
7294 break;
7295 case MPI_EVENT_STATE_CHANGE:
7296 ds = "State Change";
7297 break;
7298 case MPI_EVENT_UNIT_ATTENTION:
7299 ds = "Unit Attention";
7300 break;
7301 case MPI_EVENT_IOC_BUS_RESET:
7302 ds = "IOC Bus Reset";
7303 break;
7304 case MPI_EVENT_EXT_BUS_RESET:
7305 ds = "External Bus Reset";
7306 break;
7307 case MPI_EVENT_RESCAN:
7308 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007309 break;
7310 case MPI_EVENT_LINK_STATUS_CHANGE:
7311 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
7312 ds = "Link Status(FAILURE) Change";
7313 else
7314 ds = "Link Status(ACTIVE) Change";
7315 break;
7316 case MPI_EVENT_LOOP_STATE_CHANGE:
7317 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
7318 ds = "Loop State(LIP) Change";
7319 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Kashyap, Desai2f187862009-05-29 16:52:37 +05307320 ds = "Loop State(LPE) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007321 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05307322 ds = "Loop State(LPB) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007323 break;
7324 case MPI_EVENT_LOGOUT:
7325 ds = "Logout";
7326 break;
7327 case MPI_EVENT_EVENT_CHANGE:
7328 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06007329 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007330 else
Eric Moore4f766dc2006-07-11 17:24:07 -06007331 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007332 break;
7333 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007334 {
7335 u8 ReasonCode = (u8)(evData0 >> 16);
7336 switch (ReasonCode) {
7337 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
7338 ds = "Integrated Raid: Volume Created";
7339 break;
7340 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
7341 ds = "Integrated Raid: Volume Deleted";
7342 break;
7343 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
7344 ds = "Integrated Raid: Volume Settings Changed";
7345 break;
7346 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
7347 ds = "Integrated Raid: Volume Status Changed";
7348 break;
7349 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
7350 ds = "Integrated Raid: Volume Physdisk Changed";
7351 break;
7352 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
7353 ds = "Integrated Raid: Physdisk Created";
7354 break;
7355 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
7356 ds = "Integrated Raid: Physdisk Deleted";
7357 break;
7358 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
7359 ds = "Integrated Raid: Physdisk Settings Changed";
7360 break;
7361 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
7362 ds = "Integrated Raid: Physdisk Status Changed";
7363 break;
7364 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
7365 ds = "Integrated Raid: Domain Validation Needed";
7366 break;
7367 case MPI_EVENT_RAID_RC_SMART_DATA :
7368 ds = "Integrated Raid; Smart Data";
7369 break;
7370 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
7371 ds = "Integrated Raid: Replace Action Started";
7372 break;
7373 default:
7374 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007375 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007376 }
7377 break;
7378 }
7379 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
7380 ds = "SCSI Device Status Change";
7381 break;
7382 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
7383 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007384 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007385 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007386 u8 ReasonCode = (u8)(evData0 >> 16);
7387 switch (ReasonCode) {
7388 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007389 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007390 "SAS Device Status Change: Added: "
7391 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007392 break;
7393 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06007394 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007395 "SAS Device Status Change: Deleted: "
7396 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007397 break;
7398 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06007399 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007400 "SAS Device Status Change: SMART Data: "
7401 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007402 break;
7403 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007404 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007405 "SAS Device Status Change: No Persistancy: "
7406 "id=%d channel=%d", id, channel);
7407 break;
7408 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
7409 snprintf(evStr, EVENT_DESCR_STR_SZ,
7410 "SAS Device Status Change: Unsupported Device "
7411 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007412 break;
7413 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
7414 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007415 "SAS Device Status Change: Internal Device "
7416 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007417 break;
7418 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
7419 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007420 "SAS Device Status Change: Internal Task "
7421 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007422 break;
7423 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
7424 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007425 "SAS Device Status Change: Internal Abort "
7426 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007427 break;
7428 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
7429 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007430 "SAS Device Status Change: Internal Clear "
7431 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007432 break;
7433 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
7434 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007435 "SAS Device Status Change: Internal Query "
7436 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007437 break;
7438 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007439 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007440 "SAS Device Status Change: Unknown: "
7441 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06007442 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007443 }
7444 break;
7445 }
7446 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
7447 ds = "Bus Timer Expired";
7448 break;
7449 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07007450 {
7451 u16 curr_depth = (u16)(evData0 >> 16);
7452 u8 channel = (u8)(evData0 >> 8);
7453 u8 id = (u8)(evData0);
7454
7455 snprintf(evStr, EVENT_DESCR_STR_SZ,
7456 "Queue Full: channel=%d id=%d depth=%d",
7457 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007458 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07007459 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007460 case MPI_EVENT_SAS_SES:
7461 ds = "SAS SES Event";
7462 break;
7463 case MPI_EVENT_PERSISTENT_TABLE_FULL:
7464 ds = "Persistent Table Full";
7465 break;
7466 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07007467 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007468 u8 LinkRates = (u8)(evData0 >> 8);
7469 u8 PhyNumber = (u8)(evData0);
7470 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
7471 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
7472 switch (LinkRates) {
7473 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06007474 snprintf(evStr, EVENT_DESCR_STR_SZ,
7475 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007476 " Rate Unknown",PhyNumber);
7477 break;
7478 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06007479 snprintf(evStr, EVENT_DESCR_STR_SZ,
7480 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007481 " Phy Disabled",PhyNumber);
7482 break;
7483 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06007484 snprintf(evStr, EVENT_DESCR_STR_SZ,
7485 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007486 " Failed Speed Nego",PhyNumber);
7487 break;
7488 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06007489 snprintf(evStr, EVENT_DESCR_STR_SZ,
7490 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007491 " Sata OOB Completed",PhyNumber);
7492 break;
7493 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06007494 snprintf(evStr, EVENT_DESCR_STR_SZ,
7495 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007496 " Rate 1.5 Gbps",PhyNumber);
7497 break;
7498 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06007499 snprintf(evStr, EVENT_DESCR_STR_SZ,
7500 "SAS PHY Link Status: Phy=%d:"
Kashyap, Desaid75733d2011-02-10 11:50:39 +05307501 " Rate 3.0 Gbps", PhyNumber);
7502 break;
7503 case MPI_EVENT_SAS_PLS_LR_RATE_6_0:
7504 snprintf(evStr, EVENT_DESCR_STR_SZ,
7505 "SAS PHY Link Status: Phy=%d:"
7506 " Rate 6.0 Gbps", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007507 break;
7508 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007509 snprintf(evStr, EVENT_DESCR_STR_SZ,
7510 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007511 break;
7512 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007513 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007514 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007515 case MPI_EVENT_SAS_DISCOVERY_ERROR:
7516 ds = "SAS Discovery Error";
7517 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007518 case MPI_EVENT_IR_RESYNC_UPDATE:
7519 {
7520 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06007521 snprintf(evStr, EVENT_DESCR_STR_SZ,
7522 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07007523 break;
7524 }
7525 case MPI_EVENT_IR2:
7526 {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307527 u8 id = (u8)(evData0);
7528 u8 channel = (u8)(evData0 >> 8);
7529 u8 phys_num = (u8)(evData0 >> 24);
Moore, Eric3a892be2006-03-14 09:14:03 -07007530 u8 ReasonCode = (u8)(evData0 >> 16);
Kashyap, Desai2f187862009-05-29 16:52:37 +05307531
Moore, Eric3a892be2006-03-14 09:14:03 -07007532 switch (ReasonCode) {
7533 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307534 snprintf(evStr, EVENT_DESCR_STR_SZ,
7535 "IR2: LD State Changed: "
7536 "id=%d channel=%d phys_num=%d",
7537 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007538 break;
7539 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307540 snprintf(evStr, EVENT_DESCR_STR_SZ,
7541 "IR2: PD State Changed "
7542 "id=%d channel=%d phys_num=%d",
7543 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007544 break;
7545 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307546 snprintf(evStr, EVENT_DESCR_STR_SZ,
7547 "IR2: Bad Block Table Full: "
7548 "id=%d channel=%d phys_num=%d",
7549 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007550 break;
7551 case MPI_EVENT_IR2_RC_PD_INSERTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307552 snprintf(evStr, EVENT_DESCR_STR_SZ,
7553 "IR2: PD Inserted: "
7554 "id=%d channel=%d phys_num=%d",
7555 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007556 break;
7557 case MPI_EVENT_IR2_RC_PD_REMOVED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307558 snprintf(evStr, EVENT_DESCR_STR_SZ,
7559 "IR2: PD Removed: "
7560 "id=%d channel=%d phys_num=%d",
7561 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007562 break;
7563 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307564 snprintf(evStr, EVENT_DESCR_STR_SZ,
7565 "IR2: Foreign CFG Detected: "
7566 "id=%d channel=%d phys_num=%d",
7567 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007568 break;
7569 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307570 snprintf(evStr, EVENT_DESCR_STR_SZ,
7571 "IR2: Rebuild Medium Error: "
7572 "id=%d channel=%d phys_num=%d",
7573 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007574 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05307575 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
7576 snprintf(evStr, EVENT_DESCR_STR_SZ,
7577 "IR2: Dual Port Added: "
7578 "id=%d channel=%d phys_num=%d",
7579 id, channel, phys_num);
7580 break;
7581 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
7582 snprintf(evStr, EVENT_DESCR_STR_SZ,
7583 "IR2: Dual Port Removed: "
7584 "id=%d channel=%d phys_num=%d",
7585 id, channel, phys_num);
7586 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007587 default:
7588 ds = "IR2";
7589 break;
7590 }
7591 break;
7592 }
7593 case MPI_EVENT_SAS_DISCOVERY:
7594 {
7595 if (evData0)
7596 ds = "SAS Discovery: Start";
7597 else
7598 ds = "SAS Discovery: Stop";
7599 break;
7600 }
7601 case MPI_EVENT_LOG_ENTRY_ADDED:
7602 ds = "SAS Log Entry Added";
7603 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007604
Eric Moorec6c727a2007-01-29 09:44:54 -07007605 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
7606 {
7607 u8 phy_num = (u8)(evData0);
7608 u8 port_num = (u8)(evData0 >> 8);
7609 u8 port_width = (u8)(evData0 >> 16);
7610 u8 primative = (u8)(evData0 >> 24);
7611 snprintf(evStr, EVENT_DESCR_STR_SZ,
7612 "SAS Broadcase Primative: phy=%d port=%d "
7613 "width=%d primative=0x%02x",
7614 phy_num, port_num, port_width, primative);
7615 break;
7616 }
7617
7618 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7619 {
7620 u8 reason = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007621
Kashyap, Desai2f187862009-05-29 16:52:37 +05307622 switch (reason) {
7623 case MPI_EVENT_SAS_INIT_RC_ADDED:
7624 ds = "SAS Initiator Status Change: Added";
7625 break;
7626 case MPI_EVENT_SAS_INIT_RC_REMOVED:
7627 ds = "SAS Initiator Status Change: Deleted";
7628 break;
7629 default:
7630 ds = "SAS Initiator Status Change";
7631 break;
7632 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007633 break;
7634 }
7635
7636 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7637 {
7638 u8 max_init = (u8)(evData0);
7639 u8 current_init = (u8)(evData0 >> 8);
7640
7641 snprintf(evStr, EVENT_DESCR_STR_SZ,
7642 "SAS Initiator Device Table Overflow: max initiators=%02d "
7643 "current initators=%02d",
7644 max_init, current_init);
7645 break;
7646 }
7647 case MPI_EVENT_SAS_SMP_ERROR:
7648 {
7649 u8 status = (u8)(evData0);
7650 u8 port_num = (u8)(evData0 >> 8);
7651 u8 result = (u8)(evData0 >> 16);
7652
7653 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7654 snprintf(evStr, EVENT_DESCR_STR_SZ,
7655 "SAS SMP Error: port=%d result=0x%02x",
7656 port_num, result);
7657 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7658 snprintf(evStr, EVENT_DESCR_STR_SZ,
7659 "SAS SMP Error: port=%d : CRC Error",
7660 port_num);
7661 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7662 snprintf(evStr, EVENT_DESCR_STR_SZ,
7663 "SAS SMP Error: port=%d : Timeout",
7664 port_num);
7665 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7666 snprintf(evStr, EVENT_DESCR_STR_SZ,
7667 "SAS SMP Error: port=%d : No Destination",
7668 port_num);
7669 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7670 snprintf(evStr, EVENT_DESCR_STR_SZ,
7671 "SAS SMP Error: port=%d : Bad Destination",
7672 port_num);
7673 else
7674 snprintf(evStr, EVENT_DESCR_STR_SZ,
7675 "SAS SMP Error: port=%d : status=0x%02x",
7676 port_num, status);
7677 break;
7678 }
7679
Kashyap, Desai2f187862009-05-29 16:52:37 +05307680 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
7681 {
7682 u8 reason = (u8)(evData0);
7683
7684 switch (reason) {
7685 case MPI_EVENT_SAS_EXP_RC_ADDED:
7686 ds = "Expander Status Change: Added";
7687 break;
7688 case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
7689 ds = "Expander Status Change: Deleted";
7690 break;
7691 default:
7692 ds = "Expander Status Change";
7693 break;
7694 }
7695 break;
7696 }
7697
Linus Torvalds1da177e2005-04-16 15:20:36 -07007698 /*
7699 * MPT base "custom" events may be added here...
7700 */
7701 default:
7702 ds = "Unknown";
7703 break;
7704 }
Eric Moore509e5e52006-04-26 13:22:37 -06007705 if (ds)
7706 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007707
Kashyap, Desai2f187862009-05-29 16:52:37 +05307708
7709 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7710 "MPT event:(%02Xh) : %s\n",
7711 ioc->name, event, evStr));
7712
7713 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
7714 ": Event data:\n"));
7715 for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
7716 devtverboseprintk(ioc, printk(" %08x",
7717 le32_to_cpu(pEventReply->Data[ii])));
7718 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
7719}
7720#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007721/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007722/**
7723 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007724 * @ioc: Pointer to MPT_ADAPTER structure
7725 * @pEventReply: Pointer to EventNotification reply frame
7726 * @evHandlers: Pointer to integer, number of event handlers
7727 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007728 * Routes a received EventNotificationReply to all currently registered
7729 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007730 * Returns sum of event handlers return values.
7731 */
7732static int
7733ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7734{
7735 u16 evDataLen;
7736 u32 evData0 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007737 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307738 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007739 int r = 0;
7740 int handlers = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007741 u8 event;
7742
7743 /*
7744 * Do platform normalization of values
7745 */
7746 event = le32_to_cpu(pEventReply->Event) & 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007747 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7748 if (evDataLen) {
7749 evData0 = le32_to_cpu(pEventReply->Data[0]);
7750 }
7751
Prakash, Sathya436ace72007-07-24 15:42:08 +05307752#ifdef CONFIG_FUSION_LOGGING
Kashyap, Desai2f187862009-05-29 16:52:37 +05307753 if (evDataLen)
7754 mpt_display_event_info(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007755#endif
7756
7757 /*
7758 * Do general / base driver event processing
7759 */
7760 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007761 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7762 if (evDataLen) {
7763 u8 evState = evData0 & 0xFF;
7764
7765 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7766
7767 /* Update EventState field in cached IocFacts */
7768 if (ioc->facts.Function) {
7769 ioc->facts.EventState = evState;
7770 }
7771 }
7772 break;
Moore, Ericece50912006-01-16 18:53:19 -07007773 case MPI_EVENT_INTEGRATED_RAID:
7774 mptbase_raid_process_event_data(ioc,
7775 (MpiEventDataRaid_t *)pEventReply->Data);
7776 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007777 default:
7778 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007779 }
7780
7781 /*
7782 * Should this event be logged? Events are written sequentially.
7783 * When buffer is full, start again at the top.
7784 */
7785 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7786 int idx;
7787
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007788 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007789
7790 ioc->events[idx].event = event;
7791 ioc->events[idx].eventContext = ioc->eventContext;
7792
7793 for (ii = 0; ii < 2; ii++) {
7794 if (ii < evDataLen)
7795 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7796 else
7797 ioc->events[idx].data[ii] = 0;
7798 }
7799
7800 ioc->eventContext++;
7801 }
7802
7803
7804 /*
7805 * Call each currently registered protocol event handler.
7806 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007807 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307808 if (MptEvHandlers[cb_idx]) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307809 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7810 "Routing Event to event handler #%d\n",
7811 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307812 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007813 handlers++;
7814 }
7815 }
7816 /* FIXME? Examine results here? */
7817
7818 /*
7819 * If needed, send (a single) EventAck.
7820 */
7821 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307822 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007823 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007824 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307825 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007826 ioc->name, ii));
7827 }
7828 }
7829
7830 *evHandlers = handlers;
7831 return r;
7832}
7833
7834/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007835/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007836 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7837 * @ioc: Pointer to MPT_ADAPTER structure
7838 * @log_info: U32 LogInfo reply word from the IOC
7839 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007840 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007841 */
7842static void
7843mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7844{
Eric Moore7c431e52007-06-13 16:34:36 -06007845 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007846
Eric Moore7c431e52007-06-13 16:34:36 -06007847 switch (log_info & 0xFF000000) {
7848 case MPI_IOCLOGINFO_FC_INIT_BASE:
7849 desc = "FCP Initiator";
7850 break;
7851 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7852 desc = "FCP Target";
7853 break;
7854 case MPI_IOCLOGINFO_FC_LAN_BASE:
7855 desc = "LAN";
7856 break;
7857 case MPI_IOCLOGINFO_FC_MSG_BASE:
7858 desc = "MPI Message Layer";
7859 break;
7860 case MPI_IOCLOGINFO_FC_LINK_BASE:
7861 desc = "FC Link";
7862 break;
7863 case MPI_IOCLOGINFO_FC_CTX_BASE:
7864 desc = "Context Manager";
7865 break;
7866 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7867 desc = "Invalid Field Offset";
7868 break;
7869 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7870 desc = "State Change Info";
7871 break;
7872 }
7873
7874 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7875 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007876}
7877
7878/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007879/**
Moore, Eric335a9412006-01-17 17:06:23 -07007880 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007881 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007882 * @log_info: U32 LogInfo word from the IOC
7883 *
7884 * Refer to lsi/sp_log.h.
7885 */
7886static void
Moore, Eric335a9412006-01-17 17:06:23 -07007887mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007888{
7889 u32 info = log_info & 0x00FF0000;
7890 char *desc = "unknown";
7891
7892 switch (info) {
7893 case 0x00010000:
7894 desc = "bug! MID not found";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007895 break;
7896
7897 case 0x00020000:
7898 desc = "Parity Error";
7899 break;
7900
7901 case 0x00030000:
7902 desc = "ASYNC Outbound Overrun";
7903 break;
7904
7905 case 0x00040000:
7906 desc = "SYNC Offset Error";
7907 break;
7908
7909 case 0x00050000:
7910 desc = "BM Change";
7911 break;
7912
7913 case 0x00060000:
7914 desc = "Msg In Overflow";
7915 break;
7916
7917 case 0x00070000:
7918 desc = "DMA Error";
7919 break;
7920
7921 case 0x00080000:
7922 desc = "Outbound DMA Overrun";
7923 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007924
Linus Torvalds1da177e2005-04-16 15:20:36 -07007925 case 0x00090000:
7926 desc = "Task Management";
7927 break;
7928
7929 case 0x000A0000:
7930 desc = "Device Problem";
7931 break;
7932
7933 case 0x000B0000:
7934 desc = "Invalid Phase Change";
7935 break;
7936
7937 case 0x000C0000:
7938 desc = "Untagged Table Size";
7939 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007940
Linus Torvalds1da177e2005-04-16 15:20:36 -07007941 }
7942
7943 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7944}
7945
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007946/* strings for sas loginfo */
7947 static char *originator_str[] = {
7948 "IOP", /* 00h */
7949 "PL", /* 01h */
7950 "IR" /* 02h */
7951 };
7952 static char *iop_code_str[] = {
7953 NULL, /* 00h */
7954 "Invalid SAS Address", /* 01h */
7955 NULL, /* 02h */
7956 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007957 "Diag Message Error", /* 04h */
7958 "Task Terminated", /* 05h */
7959 "Enclosure Management", /* 06h */
7960 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007961 };
7962 static char *pl_code_str[] = {
7963 NULL, /* 00h */
7964 "Open Failure", /* 01h */
7965 "Invalid Scatter Gather List", /* 02h */
7966 "Wrong Relative Offset or Frame Length", /* 03h */
7967 "Frame Transfer Error", /* 04h */
7968 "Transmit Frame Connected Low", /* 05h */
7969 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7970 "SATA Read Log Receive Data Error", /* 07h */
7971 "SATA NCQ Fail All Commands After Error", /* 08h */
7972 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7973 "Receive Frame Invalid Message", /* 0Ah */
7974 "Receive Context Message Valid Error", /* 0Bh */
7975 "Receive Frame Current Frame Error", /* 0Ch */
7976 "SATA Link Down", /* 0Dh */
7977 "Discovery SATA Init W IOS", /* 0Eh */
7978 "Config Invalid Page", /* 0Fh */
7979 "Discovery SATA Init Timeout", /* 10h */
7980 "Reset", /* 11h */
7981 "Abort", /* 12h */
7982 "IO Not Yet Executed", /* 13h */
7983 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007984 "Persistent Reservation Out Not Affiliation "
7985 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007986 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007987 "IO Device Missing Delay Retry", /* 17h */
Lucas De Marchi25985ed2011-03-30 22:57:33 -03007988 "IO Cancelled Due to Receive Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007989 NULL, /* 19h */
7990 NULL, /* 1Ah */
7991 NULL, /* 1Bh */
7992 NULL, /* 1Ch */
7993 NULL, /* 1Dh */
7994 NULL, /* 1Eh */
7995 NULL, /* 1Fh */
7996 "Enclosure Management" /* 20h */
7997 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007998 static char *ir_code_str[] = {
7999 "Raid Action Error", /* 00h */
8000 NULL, /* 00h */
8001 NULL, /* 01h */
8002 NULL, /* 02h */
8003 NULL, /* 03h */
8004 NULL, /* 04h */
8005 NULL, /* 05h */
8006 NULL, /* 06h */
8007 NULL /* 07h */
8008 };
8009 static char *raid_sub_code_str[] = {
8010 NULL, /* 00h */
8011 "Volume Creation Failed: Data Passed too "
8012 "Large", /* 01h */
8013 "Volume Creation Failed: Duplicate Volumes "
8014 "Attempted", /* 02h */
8015 "Volume Creation Failed: Max Number "
8016 "Supported Volumes Exceeded", /* 03h */
8017 "Volume Creation Failed: DMA Error", /* 04h */
8018 "Volume Creation Failed: Invalid Volume Type", /* 05h */
8019 "Volume Creation Failed: Error Reading "
8020 "MFG Page 4", /* 06h */
8021 "Volume Creation Failed: Creating Internal "
8022 "Structures", /* 07h */
8023 NULL, /* 08h */
8024 NULL, /* 09h */
8025 NULL, /* 0Ah */
8026 NULL, /* 0Bh */
8027 NULL, /* 0Ch */
8028 NULL, /* 0Dh */
8029 NULL, /* 0Eh */
8030 NULL, /* 0Fh */
8031 "Activation failed: Already Active Volume", /* 10h */
8032 "Activation failed: Unsupported Volume Type", /* 11h */
8033 "Activation failed: Too Many Active Volumes", /* 12h */
8034 "Activation failed: Volume ID in Use", /* 13h */
8035 "Activation failed: Reported Failure", /* 14h */
8036 "Activation failed: Importing a Volume", /* 15h */
8037 NULL, /* 16h */
8038 NULL, /* 17h */
8039 NULL, /* 18h */
8040 NULL, /* 19h */
8041 NULL, /* 1Ah */
8042 NULL, /* 1Bh */
8043 NULL, /* 1Ch */
8044 NULL, /* 1Dh */
8045 NULL, /* 1Eh */
8046 NULL, /* 1Fh */
8047 "Phys Disk failed: Too Many Phys Disks", /* 20h */
8048 "Phys Disk failed: Data Passed too Large", /* 21h */
8049 "Phys Disk failed: DMA Error", /* 22h */
8050 "Phys Disk failed: Invalid <channel:id>", /* 23h */
8051 "Phys Disk failed: Creating Phys Disk Config "
8052 "Page", /* 24h */
8053 NULL, /* 25h */
8054 NULL, /* 26h */
8055 NULL, /* 27h */
8056 NULL, /* 28h */
8057 NULL, /* 29h */
8058 NULL, /* 2Ah */
8059 NULL, /* 2Bh */
8060 NULL, /* 2Ch */
8061 NULL, /* 2Dh */
8062 NULL, /* 2Eh */
8063 NULL, /* 2Fh */
8064 "Compatibility Error: IR Disabled", /* 30h */
Uwe Kleine-Königb5950762010-11-01 15:38:34 -04008065 "Compatibility Error: Inquiry Command Failed", /* 31h */
Eric Moorec6c727a2007-01-29 09:44:54 -07008066 "Compatibility Error: Device not Direct Access "
8067 "Device ", /* 32h */
8068 "Compatibility Error: Removable Device Found", /* 33h */
8069 "Compatibility Error: Device SCSI Version not "
8070 "2 or Higher", /* 34h */
8071 "Compatibility Error: SATA Device, 48 BIT LBA "
8072 "not Supported", /* 35h */
8073 "Compatibility Error: Device doesn't have "
8074 "512 Byte Block Sizes", /* 36h */
8075 "Compatibility Error: Volume Type Check Failed", /* 37h */
8076 "Compatibility Error: Volume Type is "
8077 "Unsupported by FW", /* 38h */
8078 "Compatibility Error: Disk Drive too Small for "
8079 "use in Volume", /* 39h */
8080 "Compatibility Error: Phys Disk for Create "
8081 "Volume not Found", /* 3Ah */
8082 "Compatibility Error: Too Many or too Few "
8083 "Disks for Volume Type", /* 3Bh */
8084 "Compatibility Error: Disk stripe Sizes "
8085 "Must be 64KB", /* 3Ch */
8086 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
8087 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008088
8089/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008090/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008091 * mpt_sas_log_info - Log information returned from SAS IOC.
8092 * @ioc: Pointer to MPT_ADAPTER structure
8093 * @log_info: U32 LogInfo reply word from the IOC
Randy Dunlapfc58fb12010-08-14 13:05:57 -07008094 * @cb_idx: callback function's handle
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008095 *
8096 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008097 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008098static void
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308099mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info, u8 cb_idx)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008100{
8101union loginfo_type {
8102 u32 loginfo;
8103 struct {
8104 u32 subcode:16;
8105 u32 code:8;
8106 u32 originator:4;
8107 u32 bus_type:4;
8108 }dw;
8109};
8110 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07008111 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008112 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07008113 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008114
8115 sas_loginfo.loginfo = log_info;
8116 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008117 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008118 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07008119
8120 originator_desc = originator_str[sas_loginfo.dw.originator];
8121
8122 switch (sas_loginfo.dw.originator) {
8123
8124 case 0: /* IOP */
8125 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008126 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008127 code_desc = iop_code_str[sas_loginfo.dw.code];
8128 break;
8129 case 1: /* PL */
8130 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008131 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008132 code_desc = pl_code_str[sas_loginfo.dw.code];
8133 break;
8134 case 2: /* IR */
8135 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008136 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008137 break;
8138 code_desc = ir_code_str[sas_loginfo.dw.code];
8139 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008140 ARRAY_SIZE(raid_sub_code_str))
Julia Lawall081f4f42010-08-05 22:27:14 +02008141 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07008142 if (sas_loginfo.dw.code == 0)
8143 sub_code_desc =
8144 raid_sub_code_str[sas_loginfo.dw.subcode];
8145 break;
8146 default:
8147 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008148 }
8149
Eric Moorec6c727a2007-01-29 09:44:54 -07008150 if (sub_code_desc != NULL)
8151 printk(MYIOC_s_INFO_FMT
8152 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308153 " SubCode={%s} cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008154 ioc->name, log_info, originator_desc, code_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308155 sub_code_desc, MptCallbacksName[cb_idx]);
Eric Moorec6c727a2007-01-29 09:44:54 -07008156 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008157 printk(MYIOC_s_INFO_FMT
8158 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308159 " SubCode(0x%04x) cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008160 ioc->name, log_info, originator_desc, code_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308161 sas_loginfo.dw.subcode, MptCallbacksName[cb_idx]);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008162 else
8163 printk(MYIOC_s_INFO_FMT
8164 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308165 " SubCode(0x%04x) cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008166 ioc->name, log_info, originator_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308167 sas_loginfo.dw.code, sas_loginfo.dw.subcode,
8168 MptCallbacksName[cb_idx]);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008169}
8170
Linus Torvalds1da177e2005-04-16 15:20:36 -07008171/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008172/**
Eric Moorec6c727a2007-01-29 09:44:54 -07008173 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
8174 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08008175 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07008176 * @mf: Pointer to MPT request frame
8177 *
8178 * Refer to lsi/mpi.h.
8179 **/
8180static void
8181mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
8182{
8183 Config_t *pReq = (Config_t *)mf;
8184 char extend_desc[EVENT_DESCR_STR_SZ];
8185 char *desc = NULL;
8186 u32 form;
8187 u8 page_type;
8188
8189 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
8190 page_type = pReq->ExtPageType;
8191 else
8192 page_type = pReq->Header.PageType;
8193
8194 /*
8195 * ignore invalid page messages for GET_NEXT_HANDLE
8196 */
8197 form = le32_to_cpu(pReq->PageAddress);
8198 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
8199 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
8200 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
8201 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
8202 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
8203 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
8204 return;
8205 }
8206 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
8207 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
8208 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
8209 return;
8210 }
8211
8212 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
8213 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
8214 page_type, pReq->Header.PageNumber, pReq->Action, form);
8215
8216 switch (ioc_status) {
8217
8218 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8219 desc = "Config Page Invalid Action";
8220 break;
8221
8222 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8223 desc = "Config Page Invalid Type";
8224 break;
8225
8226 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8227 desc = "Config Page Invalid Page";
8228 break;
8229
8230 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8231 desc = "Config Page Invalid Data";
8232 break;
8233
8234 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8235 desc = "Config Page No Defaults";
8236 break;
8237
8238 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
8239 desc = "Config Page Can't Commit";
8240 break;
8241 }
8242
8243 if (!desc)
8244 return;
8245
Eric Moore29dd3602007-09-14 18:46:51 -06008246 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
8247 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07008248}
8249
8250/**
8251 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07008252 * @ioc: Pointer to MPT_ADAPTER structure
8253 * @ioc_status: U32 IOCStatus word from IOC
8254 * @mf: Pointer to MPT request frame
8255 *
8256 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008257 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07008258static void
Eric Moorec6c727a2007-01-29 09:44:54 -07008259mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008260{
8261 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06008262 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008263
8264 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07008265
8266/****************************************************************************/
8267/* Common IOCStatus values for all replies */
8268/****************************************************************************/
8269
Linus Torvalds1da177e2005-04-16 15:20:36 -07008270 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
8271 desc = "Invalid Function";
8272 break;
8273
8274 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
8275 desc = "Busy";
8276 break;
8277
8278 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
8279 desc = "Invalid SGL";
8280 break;
8281
8282 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
8283 desc = "Internal Error";
8284 break;
8285
8286 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
8287 desc = "Reserved";
8288 break;
8289
8290 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
8291 desc = "Insufficient Resources";
8292 break;
8293
8294 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
8295 desc = "Invalid Field";
8296 break;
8297
8298 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
8299 desc = "Invalid State";
8300 break;
8301
Eric Moorec6c727a2007-01-29 09:44:54 -07008302/****************************************************************************/
8303/* Config IOCStatus values */
8304/****************************************************************************/
8305
Linus Torvalds1da177e2005-04-16 15:20:36 -07008306 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8307 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8308 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8309 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8310 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8311 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008312 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008313 break;
8314
Eric Moorec6c727a2007-01-29 09:44:54 -07008315/****************************************************************************/
8316/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
8317/* */
8318/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
8319/* */
8320/****************************************************************************/
8321
Linus Torvalds1da177e2005-04-16 15:20:36 -07008322 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008323 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008324 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
8325 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
8326 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
8327 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008328 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008329 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008330 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008331 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008332 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008333 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07008334 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008335 break;
8336
Eric Moorec6c727a2007-01-29 09:44:54 -07008337/****************************************************************************/
8338/* SCSI Target values */
8339/****************************************************************************/
8340
8341 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
8342 desc = "Target: Priority IO";
8343 break;
8344
8345 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
8346 desc = "Target: Invalid Port";
8347 break;
8348
8349 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
8350 desc = "Target Invalid IO Index:";
8351 break;
8352
8353 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
8354 desc = "Target: Aborted";
8355 break;
8356
8357 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
8358 desc = "Target: No Conn Retryable";
8359 break;
8360
8361 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
8362 desc = "Target: No Connection";
8363 break;
8364
8365 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
8366 desc = "Target: Transfer Count Mismatch";
8367 break;
8368
8369 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
8370 desc = "Target: STS Data not Sent";
8371 break;
8372
8373 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
8374 desc = "Target: Data Offset Error";
8375 break;
8376
8377 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
8378 desc = "Target: Too Much Write Data";
8379 break;
8380
8381 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
8382 desc = "Target: IU Too Short";
8383 break;
8384
8385 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
8386 desc = "Target: ACK NAK Timeout";
8387 break;
8388
8389 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
8390 desc = "Target: Nak Received";
8391 break;
8392
8393/****************************************************************************/
8394/* Fibre Channel Direct Access values */
8395/****************************************************************************/
8396
8397 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
8398 desc = "FC: Aborted";
8399 break;
8400
8401 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
8402 desc = "FC: RX ID Invalid";
8403 break;
8404
8405 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
8406 desc = "FC: DID Invalid";
8407 break;
8408
8409 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
8410 desc = "FC: Node Logged Out";
8411 break;
8412
8413 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
8414 desc = "FC: Exchange Canceled";
8415 break;
8416
8417/****************************************************************************/
8418/* LAN values */
8419/****************************************************************************/
8420
8421 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
8422 desc = "LAN: Device not Found";
8423 break;
8424
8425 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
8426 desc = "LAN: Device Failure";
8427 break;
8428
8429 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
8430 desc = "LAN: Transmit Error";
8431 break;
8432
8433 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
8434 desc = "LAN: Transmit Aborted";
8435 break;
8436
8437 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
8438 desc = "LAN: Receive Error";
8439 break;
8440
8441 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
8442 desc = "LAN: Receive Aborted";
8443 break;
8444
8445 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
8446 desc = "LAN: Partial Packet";
8447 break;
8448
8449 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
8450 desc = "LAN: Canceled";
8451 break;
8452
8453/****************************************************************************/
8454/* Serial Attached SCSI values */
8455/****************************************************************************/
8456
8457 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
8458 desc = "SAS: SMP Request Failed";
8459 break;
8460
8461 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
8462 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07008463 break;
8464
8465 default:
8466 desc = "Others";
8467 break;
8468 }
Eric Moorec6c727a2007-01-29 09:44:54 -07008469
8470 if (!desc)
8471 return;
8472
Eric Moore29dd3602007-09-14 18:46:51 -06008473 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
8474 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008475}
8476
8477/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008478EXPORT_SYMBOL(mpt_attach);
8479EXPORT_SYMBOL(mpt_detach);
8480#ifdef CONFIG_PM
8481EXPORT_SYMBOL(mpt_resume);
8482EXPORT_SYMBOL(mpt_suspend);
8483#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07008484EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008485EXPORT_SYMBOL(mpt_register);
8486EXPORT_SYMBOL(mpt_deregister);
8487EXPORT_SYMBOL(mpt_event_register);
8488EXPORT_SYMBOL(mpt_event_deregister);
8489EXPORT_SYMBOL(mpt_reset_register);
8490EXPORT_SYMBOL(mpt_reset_deregister);
8491EXPORT_SYMBOL(mpt_device_driver_register);
8492EXPORT_SYMBOL(mpt_device_driver_deregister);
8493EXPORT_SYMBOL(mpt_get_msg_frame);
8494EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05308495EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008496EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008497EXPORT_SYMBOL(mpt_send_handshake_request);
8498EXPORT_SYMBOL(mpt_verify_adapter);
8499EXPORT_SYMBOL(mpt_GetIocState);
8500EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008501EXPORT_SYMBOL(mpt_HardResetHandler);
8502EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008503EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008504EXPORT_SYMBOL(mpt_alloc_fw_memory);
8505EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02008506EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07008507EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008508
Linus Torvalds1da177e2005-04-16 15:20:36 -07008509/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008510/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008511 * fusion_init - Fusion MPT base driver initialization routine.
8512 *
8513 * Returns 0 for success, non-zero for failure.
8514 */
8515static int __init
8516fusion_init(void)
8517{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308518 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008519
8520 show_mptmod_ver(my_NAME, my_VERSION);
8521 printk(KERN_INFO COPYRIGHT "\n");
8522
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308523 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
8524 MptCallbacks[cb_idx] = NULL;
8525 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
8526 MptEvHandlers[cb_idx] = NULL;
8527 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008528 }
8529
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008530 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07008531 * EventNotification handling.
8532 */
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308533 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER,
8534 "mptbase_reply");
Linus Torvalds1da177e2005-04-16 15:20:36 -07008535
8536 /* Register for hard reset handling callbacks.
8537 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05308538 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008539
8540#ifdef CONFIG_PROC_FS
8541 (void) procmpt_create();
8542#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008543 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008544}
8545
8546/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008547/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008548 * fusion_exit - Perform driver unload cleanup.
8549 *
8550 * This routine frees all resources associated with each MPT adapter
8551 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
8552 */
8553static void __exit
8554fusion_exit(void)
8555{
8556
Linus Torvalds1da177e2005-04-16 15:20:36 -07008557 mpt_reset_deregister(mpt_base_index);
8558
8559#ifdef CONFIG_PROC_FS
8560 procmpt_destroy();
8561#endif
8562}
8563
Linus Torvalds1da177e2005-04-16 15:20:36 -07008564module_init(fusion_init);
8565module_exit(fusion_exit);