blob: 207370d68c1740c3d44e341c1824bb01da46c20d [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;
James Bottomleydb47c2d2007-07-28 13:40:21 -0400102static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
103module_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
James Bottomleydb47c2d2007-07-28 13:40:21 -0400245static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
246{
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)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001804 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 return r;
1806 }
1807
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301808 /*
1809 * Setting up proper handlers for scatter gather handling
1810 */
1811 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
1812 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
1813 ioc->add_sge = &mpt_add_sge_64bit_1078;
1814 else
1815 ioc->add_sge = &mpt_add_sge_64bit;
1816 ioc->add_chain = &mpt_add_chain_64bit;
1817 ioc->sg_addr_size = 8;
1818 } else {
1819 ioc->add_sge = &mpt_add_sge;
1820 ioc->add_chain = &mpt_add_chain;
1821 ioc->sg_addr_size = 4;
1822 }
1823 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
1824
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 ioc->alloc_total = sizeof(MPT_ADAPTER);
1826 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1827 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001828
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301830 spin_lock_init(&ioc->taskmgmt_lock);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05301831 mutex_init(&ioc->internal_cmds.mutex);
1832 init_completion(&ioc->internal_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301833 mutex_init(&ioc->mptbase_cmds.mutex);
1834 init_completion(&ioc->mptbase_cmds.done);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301835 mutex_init(&ioc->taskmgmt_cmds.mutex);
1836 init_completion(&ioc->taskmgmt_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301837
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 /* Initialize the event logging.
1839 */
1840 ioc->eventTypes = 0; /* None */
1841 ioc->eventContext = 0;
1842 ioc->eventLogSize = 0;
1843 ioc->events = NULL;
1844
1845#ifdef MFCNT
1846 ioc->mfcnt = 0;
1847#endif
1848
Kashyap, Desai2f187862009-05-29 16:52:37 +05301849 ioc->sh = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 ioc->cached_fw = NULL;
1851
Uwe Kleine-König421f91d2010-06-11 12:17:00 +02001852 /* Initialize SCSI Config Data structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001854 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855
Michael Reed05e8ec12006-01-13 14:31:54 -06001856 /* Initialize the fc rport list head.
1857 */
1858 INIT_LIST_HEAD(&ioc->fc_rports);
1859
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 /* Find lookup slot. */
1861 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001862
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301863
1864 /* Initialize workqueue */
1865 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301866
Kashyap, Desai2f187862009-05-29 16:52:37 +05301867 snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN,
Kay Sieversaab0de22008-05-02 06:02:41 +02001868 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301869 ioc->reset_work_q =
1870 create_singlethread_workqueue(ioc->reset_work_q_name);
1871 if (!ioc->reset_work_q) {
1872 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1873 ioc->name);
1874 pci_release_selected_regions(pdev, ioc->bars);
1875 kfree(ioc);
1876 return -ENOMEM;
1877 }
1878
Eric Moore29dd3602007-09-14 18:46:51 -06001879 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1880 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
Joe Lawrencec9834c72014-06-25 17:06:28 -04001882 ioc->prod_name = mpt_get_product_name(pdev->vendor, pdev->device,
1883 pdev->revision);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301884
1885 switch (pdev->device)
1886 {
1887 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1888 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1889 ioc->errata_flag_1064 = 1;
1890 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1891 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1892 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1893 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301895 break;
1896
1897 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Sergei Shtylyov9ceb5c12012-05-31 16:26:06 -07001898 if (pdev->revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 /* 929X Chip Fix. Set Split transactions level
1900 * for PCIX. Set MOST bits to zero.
1901 */
1902 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1903 pcixcmd &= 0x8F;
1904 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1905 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 /* 929XL Chip Fix. Set MMRBC to 0x08.
1907 */
1908 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1909 pcixcmd |= 0x08;
1910 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1911 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301913 break;
1914
1915 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 /* 919X Chip Fix. Set Split transactions level
1917 * for PCIX. Set MOST bits to zero.
1918 */
1919 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1920 pcixcmd &= 0x8F;
1921 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001922 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301923 break;
1924
1925 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 /* 1030 Chip Fix. Disable Split transactions
1927 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1928 */
Sergei Shtylyov9ceb5c12012-05-31 16:26:06 -07001929 if (pdev->revision < C0_1030) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1931 pcixcmd &= 0x8F;
1932 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1933 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301934
1935 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001936 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301937 break;
1938
1939 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1940 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001941 ioc->errata_flag_1064 = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301942 ioc->bus_type = SAS;
1943 break;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301944
1945 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1946 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1947 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001948 ioc->bus_type = SAS;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301949 break;
Eric Moore87cf8982006-06-27 16:09:26 -06001950 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301952
Kashyap, Desaie3829682009-01-08 14:27:16 +05301953 switch (ioc->bus_type) {
1954
1955 case SAS:
1956 ioc->msi_enable = mpt_msi_enable_sas;
1957 break;
1958
1959 case SPI:
1960 ioc->msi_enable = mpt_msi_enable_spi;
1961 break;
1962
1963 case FC:
1964 ioc->msi_enable = mpt_msi_enable_fc;
1965 break;
1966
1967 default:
1968 ioc->msi_enable = 0;
1969 break;
1970 }
Kashyap, Desai8ce13de2010-06-17 14:35:46 +05301971
1972 ioc->fw_events_off = 1;
1973
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001974 if (ioc->errata_flag_1064)
1975 pci_disable_io_access(pdev);
1976
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 spin_lock_init(&ioc->FreeQlock);
1978
1979 /* Disable all! */
1980 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1981 ioc->active = 0;
1982 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1983
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301984 /* Set IOC ptr in the pcidev's driver data. */
1985 pci_set_drvdata(ioc->pcidev, ioc);
1986
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 /* Set lookup ptr. */
1988 list_add_tail(&ioc->list, &ioc_list);
1989
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001990 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 */
1992 mpt_detect_bound_ports(ioc, pdev);
1993
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301994 INIT_LIST_HEAD(&ioc->fw_event_list);
1995 spin_lock_init(&ioc->fw_event_lock);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301996 snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301997 ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
1998
James Bottomleyc92f2222006-03-01 09:02:49 -06001999 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2000 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06002001 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
2002 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06002003
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07002005 if (ioc->alt_ioc)
2006 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302007 iounmap(ioc->memmap);
2008 if (r != -5)
2009 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302010
2011 destroy_workqueue(ioc->reset_work_q);
2012 ioc->reset_work_q = NULL;
2013
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 kfree(ioc);
2015 pci_set_drvdata(pdev, NULL);
2016 return r;
2017 }
2018
2019 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002020 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302021 if(MptDeviceDriverHandlers[cb_idx] &&
2022 MptDeviceDriverHandlers[cb_idx]->probe) {
2023 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 }
2025 }
2026
2027#ifdef CONFIG_PROC_FS
2028 /*
2029 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
2030 */
2031 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
2032 if (dent) {
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07002033 proc_create_data("info", S_IRUGO, dent, &mpt_iocinfo_proc_fops, ioc);
2034 proc_create_data("summary", S_IRUGO, dent, &mpt_summary_proc_fops, ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 }
2036#endif
2037
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302038 if (!ioc->alt_ioc)
2039 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
2040 msecs_to_jiffies(MPT_POLLING_INTERVAL));
2041
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 return 0;
2043}
2044
2045/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002046/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002047 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 */
2050
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002051void
2052mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053{
2054 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2055 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302056 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302057 unsigned long flags;
2058 struct workqueue_struct *wq;
2059
2060 /*
2061 * Stop polling ioc for fault condition
2062 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302063 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302064 wq = ioc->reset_work_q;
2065 ioc->reset_work_q = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302066 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302067 cancel_delayed_work(&ioc->fault_reset_work);
2068 destroy_workqueue(wq);
2069
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05302070 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2071 wq = ioc->fw_event_q;
2072 ioc->fw_event_q = NULL;
2073 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2074 destroy_workqueue(wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075
2076 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2077 remove_proc_entry(pname, NULL);
2078 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2079 remove_proc_entry(pname, NULL);
2080 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2081 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002082
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002084 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302085 if(MptDeviceDriverHandlers[cb_idx] &&
2086 MptDeviceDriverHandlers[cb_idx]->remove) {
2087 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 }
2089 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002090
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 /* Disable interrupts! */
2092 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2093
2094 ioc->active = 0;
2095 synchronize_irq(pdev->irq);
2096
2097 /* Clear any lingering interrupt */
2098 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2099
2100 CHIPREG_READ32(&ioc->chip->IntStatus);
2101
2102 mpt_adapter_dispose(ioc);
2103
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104}
2105
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106/**************************************************************************
2107 * Power Management
2108 */
2109#ifdef CONFIG_PM
2110/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002111/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002112 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002113 * @pdev: Pointer to pci_dev structure
2114 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002116int
2117mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118{
2119 u32 device_state;
2120 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302122 device_state = pci_choose_state(pdev, state);
2123 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2124 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2125 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126
2127 /* put ioc into READY_STATE */
2128 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2129 printk(MYIOC_s_ERR_FMT
2130 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2131 }
2132
2133 /* disable interrupts */
2134 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2135 ioc->active = 0;
2136
2137 /* Clear any lingering interrupt */
2138 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2139
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302140 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002141 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302142 pci_disable_msi(ioc->pcidev);
2143 ioc->pci_irq = -1;
2144 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302146 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 return 0;
2149}
2150
2151/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002152/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002153 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002154 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002156int
2157mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158{
2159 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2160 u32 device_state = pdev->current_state;
2161 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302162 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002163
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302164 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2165 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2166 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302168 pci_set_power_state(pdev, PCI_D0);
2169 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302171 ioc->pcidev = pdev;
2172 err = mpt_mapresources(ioc);
2173 if (err)
2174 return err;
2175
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302176 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2177 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2178 ioc->add_sge = &mpt_add_sge_64bit_1078;
2179 else
2180 ioc->add_sge = &mpt_add_sge_64bit;
2181 ioc->add_chain = &mpt_add_chain_64bit;
2182 ioc->sg_addr_size = 8;
2183 } else {
2184
2185 ioc->add_sge = &mpt_add_sge;
2186 ioc->add_chain = &mpt_add_chain;
2187 ioc->sg_addr_size = 4;
2188 }
2189 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2190
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302191 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2192 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2193 CHIPREG_READ32(&ioc->chip->Doorbell));
2194
2195 /*
2196 * Errata workaround for SAS pci express:
2197 * Upon returning to the D0 state, the contents of the doorbell will be
2198 * stale data, and this will incorrectly signal to the host driver that
2199 * the firmware is ready to process mpt commands. The workaround is
2200 * to issue a diagnostic reset.
2201 */
2202 if (ioc->bus_type == SAS && (pdev->device ==
2203 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2204 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2205 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2206 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2207 ioc->name);
2208 goto out;
2209 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302210 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211
2212 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302213 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2214 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2215 CAN_SLEEP);
2216 if (recovery_state != 0)
2217 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2218 "error:[%x]\n", ioc->name, recovery_state);
2219 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302221 "pci-resume: success\n", ioc->name);
2222 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302224
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225}
2226#endif
2227
James Bottomley4ff42a62006-05-17 18:06:52 -05002228static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302229mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002230{
2231 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2232 ioc->bus_type != SPI) ||
2233 (MptDriverClass[index] == MPTFC_DRIVER &&
2234 ioc->bus_type != FC) ||
2235 (MptDriverClass[index] == MPTSAS_DRIVER &&
2236 ioc->bus_type != SAS))
2237 /* make sure we only call the relevant reset handler
2238 * for the bus */
2239 return 0;
2240 return (MptResetHandlers[index])(ioc, reset_phase);
2241}
2242
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002244/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2246 * @ioc: Pointer to MPT adapter structure
2247 * @reason: Event word / reason
2248 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2249 *
2250 * This routine performs all the steps necessary to bring the IOC
2251 * to a OPERATIONAL state.
2252 *
2253 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2254 * MPT adapter.
2255 *
2256 * Returns:
2257 * 0 for success
2258 * -1 if failed to get board READY
2259 * -2 if READY but IOCFacts Failed
2260 * -3 if READY but PrimeIOCFifos Failed
2261 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302262 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302263 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 */
2265static int
2266mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2267{
2268 int hard_reset_done = 0;
2269 int alt_ioc_ready = 0;
2270 int hard;
2271 int rc=0;
2272 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 int ret = 0;
2274 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002275 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302276 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277
Eric Moore29dd3602007-09-14 18:46:51 -06002278 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2279 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280
2281 /* Disable reply interrupts (also blocks FreeQ) */
2282 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2283 ioc->active = 0;
2284
2285 if (ioc->alt_ioc) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302286 if (ioc->alt_ioc->active ||
2287 reason == MPT_HOSTEVENT_IOC_RECOVER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 reset_alt_ioc_active = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302289 /* Disable alt-IOC's reply interrupts
2290 * (and FreeQ) for a bit
2291 **/
2292 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2293 0xFFFFFFFF);
2294 ioc->alt_ioc->active = 0;
2295 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 }
2297
2298 hard = 1;
2299 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2300 hard = 0;
2301
2302 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2303 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002304 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2305 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306
2307 if (reset_alt_ioc_active && ioc->alt_ioc) {
2308 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002309 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2310 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002311 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 ioc->alt_ioc->active = 1;
2313 }
2314
2315 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302316 printk(MYIOC_s_WARN_FMT
2317 "NOT READY WARNING!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302319 ret = -1;
2320 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 }
2322
2323 /* hard_reset_done = 0 if a soft reset was performed
2324 * and 1 if a hard reset was performed.
2325 */
2326 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2327 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2328 alt_ioc_ready = 1;
2329 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05302330 printk(MYIOC_s_WARN_FMT
2331 ": alt-ioc Not ready WARNING!\n",
2332 ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 }
2334
2335 for (ii=0; ii<5; ii++) {
2336 /* Get IOC facts! Allow 5 retries */
2337 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2338 break;
2339 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002340
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341
2342 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002343 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2344 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 ret = -2;
2346 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2347 MptDisplayIocCapabilities(ioc);
2348 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002349
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 if (alt_ioc_ready) {
2351 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302352 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302353 "Initial Alt IocFacts failed rc=%x\n",
2354 ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 /* Retry - alt IOC was initialized once
2356 */
2357 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2358 }
2359 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302360 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002361 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 alt_ioc_ready = 0;
2363 reset_alt_ioc_active = 0;
2364 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2365 MptDisplayIocCapabilities(ioc->alt_ioc);
2366 }
2367 }
2368
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302369 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2370 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2371 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2372 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2373 IORESOURCE_IO);
2374 if (pci_enable_device(ioc->pcidev))
2375 return -5;
2376 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2377 "mpt"))
2378 return -5;
2379 }
2380
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002381 /*
2382 * Device is reset now. It must have de-asserted the interrupt line
2383 * (if it was asserted) and it should be safe to register for the
2384 * interrupt now.
2385 */
2386 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2387 ioc->pci_irq = -1;
2388 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302389 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002390 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002391 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302392 else
2393 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002394 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002395 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002396 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002397 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Kashyap, Desai2f187862009-05-29 16:52:37 +05302398 "interrupt %d!\n",
2399 ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302400 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002401 pci_disable_msi(ioc->pcidev);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302402 ret = -EBUSY;
2403 goto out;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002404 }
2405 irq_allocated = 1;
2406 ioc->pci_irq = ioc->pcidev->irq;
2407 pci_set_master(ioc->pcidev); /* ?? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302408 pci_set_drvdata(ioc->pcidev, ioc);
2409 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2410 "installed at interrupt %d\n", ioc->name,
2411 ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002412 }
2413 }
2414
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 /* Prime reply & request queues!
2416 * (mucho alloc's) Must be done prior to
2417 * init as upper addresses are needed for init.
2418 * If fails, continue with alt-ioc processing
2419 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302420 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
2421 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2423 ret = -3;
2424
2425 /* May need to check/upload firmware & data here!
2426 * If fails, continue with alt-ioc processing
2427 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302428 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
2429 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2431 ret = -4;
2432// NEW!
2433 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302434 printk(MYIOC_s_WARN_FMT
2435 ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002436 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 alt_ioc_ready = 0;
2438 reset_alt_ioc_active = 0;
2439 }
2440
2441 if (alt_ioc_ready) {
2442 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2443 alt_ioc_ready = 0;
2444 reset_alt_ioc_active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302445 printk(MYIOC_s_WARN_FMT
2446 ": alt-ioc: (%d) init failure WARNING!\n",
2447 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 }
2449 }
2450
2451 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2452 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302453 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002454 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455
2456 /* Controller is not operational, cannot do upload
2457 */
2458 if (ret == 0) {
2459 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002460 if (rc == 0) {
2461 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2462 /*
2463 * Maintain only one pointer to FW memory
2464 * so there will not be two attempt to
2465 * downloadboot onboard dual function
2466 * chips (mpt_adapter_disable,
2467 * mpt_diag_reset)
2468 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302469 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002470 "mpt_upload: alt_%s has cached_fw=%p \n",
2471 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302472 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002473 }
2474 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002475 printk(MYIOC_s_WARN_FMT
2476 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302477 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 }
2480 }
2481 }
2482
Kashyap, Desaifd761752009-05-29 16:39:06 +05302483 /* Enable MPT base driver management of EventNotification
2484 * and EventAck handling.
2485 */
2486 if ((ret == 0) && (!ioc->facts.EventState)) {
2487 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2488 "SendEventNotification\n",
2489 ioc->name));
2490 ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
2491 }
2492
2493 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2494 rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
2495
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 if (ret == 0) {
2497 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002498 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 ioc->active = 1;
2500 }
Kashyap, Desaifd761752009-05-29 16:39:06 +05302501 if (rc == 0) { /* alt ioc */
2502 if (reset_alt_ioc_active && ioc->alt_ioc) {
2503 /* (re)Enable alt-IOC! (reply interrupt) */
2504 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
2505 "reply irq re-enabled\n",
2506 ioc->alt_ioc->name));
2507 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2508 MPI_HIM_DIM);
2509 ioc->alt_ioc->active = 1;
2510 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 }
2512
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002514 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2516 * recursive scenario; GetLanConfigPages times out, timer expired
2517 * routine calls HardResetHandler, which calls into here again,
2518 * and we try GetLanConfigPages again...
2519 */
2520 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002521
2522 /*
Uwe Kleine-König421f91d2010-06-11 12:17:00 +02002523 * Initialize link list for inactive raid volumes.
Eric Mooreb506ade2007-01-29 09:45:37 -07002524 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002525 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002526 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2527
Kashyap, Desai2f187862009-05-29 16:52:37 +05302528 switch (ioc->bus_type) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002529
Kashyap, Desai2f187862009-05-29 16:52:37 +05302530 case SAS:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002531 /* clear persistency table */
2532 if(ioc->facts.IOCExceptions &
2533 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2534 ret = mptbase_sas_persist_operation(ioc,
2535 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2536 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002537 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002538 }
2539
2540 /* Find IM volumes
2541 */
2542 mpt_findImVolumes(ioc);
2543
Kashyap, Desai2f187862009-05-29 16:52:37 +05302544 /* Check, and possibly reset, the coalescing value
2545 */
2546 mpt_read_ioc_pg_1(ioc);
2547
2548 break;
2549
2550 case FC:
2551 if ((ioc->pfacts[0].ProtocolFlags &
2552 MPI_PORTFACTS_PROTOCOL_LAN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2554 /*
2555 * Pre-fetch the ports LAN MAC address!
2556 * (LANPage1_t stuff)
2557 */
2558 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302559 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2560 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302561 "LanAddr = %02X:%02X:%02X"
2562 ":%02X:%02X:%02X\n",
2563 ioc->name, a[5], a[4],
2564 a[3], a[2], a[1], a[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302566 break;
2567
2568 case SPI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 /* Get NVRAM and adapter maximums from SPP 0 and 2
2570 */
2571 mpt_GetScsiPortSettings(ioc, 0);
2572
2573 /* Get version and length of SDP 1
2574 */
2575 mpt_readScsiDevicePageHeaders(ioc, 0);
2576
2577 /* Find IM volumes
2578 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002579 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 mpt_findImVolumes(ioc);
2581
2582 /* Check, and possibly reset, the coalescing value
2583 */
2584 mpt_read_ioc_pg_1(ioc);
2585
2586 mpt_read_ioc_pg_4(ioc);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302587
2588 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 }
2590
2591 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302592 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 }
2594
Eric Moore0ccdb002006-07-11 17:33:13 -06002595 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002596 if ((ret != 0) && irq_allocated) {
2597 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302598 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002599 pci_disable_msi(ioc->pcidev);
2600 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 return ret;
2602}
2603
2604/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002605/**
2606 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 * @ioc: Pointer to MPT adapter structure
2608 * @pdev: Pointer to (struct pci_dev) structure
2609 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002610 * Search for PCI bus/dev_function which matches
2611 * PCI bus/dev_function (+/-1) for newly discovered 929,
2612 * 929X, 1030 or 1035.
2613 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2615 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2616 */
2617static void
2618mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2619{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002620 struct pci_dev *peer=NULL;
2621 unsigned int slot = PCI_SLOT(pdev->devfn);
2622 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 MPT_ADAPTER *ioc_srch;
2624
Prakash, Sathya436ace72007-07-24 15:42:08 +05302625 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002626 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002627 ioc->name, pci_name(pdev), pdev->bus->number,
2628 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002629
2630 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2631 if (!peer) {
2632 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2633 if (!peer)
2634 return;
2635 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636
2637 list_for_each_entry(ioc_srch, &ioc_list, list) {
2638 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002639 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 /* Paranoia checks */
2641 if (ioc->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302642 printk(MYIOC_s_WARN_FMT
2643 "Oops, already bound (%s <==> %s)!\n",
2644 ioc->name, ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 break;
2646 } else if (ioc_srch->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302647 printk(MYIOC_s_WARN_FMT
2648 "Oops, already bound (%s <==> %s)!\n",
2649 ioc_srch->name, ioc_srch->name,
2650 ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 break;
2652 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302653 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2654 "FOUND! binding %s <==> %s\n",
2655 ioc->name, ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 ioc_srch->alt_ioc = ioc;
2657 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 }
2659 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002660 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661}
2662
2663/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002664/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002666 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 */
2668static void
2669mpt_adapter_disable(MPT_ADAPTER *ioc)
2670{
2671 int sz;
2672 int ret;
2673
2674 if (ioc->cached_fw != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302675 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2676 "%s: Pushing FW onto adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302677 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2678 ioc->cached_fw, CAN_SLEEP)) < 0) {
2679 printk(MYIOC_s_WARN_FMT
2680 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002681 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 }
2683 }
2684
Kashyap, Desai71278192009-05-29 16:53:14 +05302685 /*
2686 * Put the controller into ready state (if its not already)
2687 */
2688 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {
2689 if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
2690 CAN_SLEEP)) {
2691 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)
2692 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit "
2693 "reset failed to put ioc in ready state!\n",
2694 ioc->name, __func__);
2695 } else
2696 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset "
2697 "failed!\n", ioc->name, __func__);
2698 }
2699
2700
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 /* Disable adapter interrupts! */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302702 synchronize_irq(ioc->pcidev->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2704 ioc->active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302705
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 /* Clear any lingering interrupt */
2707 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302708 CHIPREG_READ32(&ioc->chip->IntStatus);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709
2710 if (ioc->alloc != NULL) {
2711 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002712 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2713 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 pci_free_consistent(ioc->pcidev, sz,
2715 ioc->alloc, ioc->alloc_dma);
2716 ioc->reply_frames = NULL;
2717 ioc->req_frames = NULL;
2718 ioc->alloc = NULL;
2719 ioc->alloc_total -= sz;
2720 }
2721
2722 if (ioc->sense_buf_pool != NULL) {
2723 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2724 pci_free_consistent(ioc->pcidev, sz,
2725 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2726 ioc->sense_buf_pool = NULL;
2727 ioc->alloc_total -= sz;
2728 }
2729
2730 if (ioc->events != NULL){
2731 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2732 kfree(ioc->events);
2733 ioc->events = NULL;
2734 ioc->alloc_total -= sz;
2735 }
2736
Prakash, Sathya984621b2008-01-11 14:42:17 +05302737 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002739 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002740 mpt_inactive_raid_list_free(ioc);
2741 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002742 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002743 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002744 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745
2746 if (ioc->spi_data.pIocPg4 != NULL) {
2747 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302748 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 ioc->spi_data.pIocPg4,
2750 ioc->spi_data.IocPg4_dma);
2751 ioc->spi_data.pIocPg4 = NULL;
2752 ioc->alloc_total -= sz;
2753 }
2754
2755 if (ioc->ReqToChain != NULL) {
2756 kfree(ioc->ReqToChain);
2757 kfree(ioc->RequestNB);
2758 ioc->ReqToChain = NULL;
2759 }
2760
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002761 kfree(ioc->ChainToChain);
2762 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002763
2764 if (ioc->HostPageBuffer != NULL) {
2765 if((ret = mpt_host_page_access_control(ioc,
2766 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002767 printk(MYIOC_s_ERR_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302768 ": %s: host page buffers free failed (%d)!\n",
2769 ioc->name, __func__, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002770 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302771 dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2772 "HostPageBuffer free @ %p, sz=%d bytes\n",
2773 ioc->name, ioc->HostPageBuffer,
2774 ioc->HostPageBuffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002775 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002776 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002777 ioc->HostPageBuffer = NULL;
2778 ioc->HostPageBuffer_sz = 0;
2779 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2780 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781
Kashyap, Desai2f187862009-05-29 16:52:37 +05302782 pci_set_drvdata(ioc->pcidev, NULL);
2783}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002785/**
2786 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 * @ioc: Pointer to MPT adapter structure
2788 *
2789 * This routine unregisters h/w resources and frees all alloc'd memory
2790 * associated with a MPT adapter structure.
2791 */
2792static void
2793mpt_adapter_dispose(MPT_ADAPTER *ioc)
2794{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002795 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002797 if (ioc == NULL)
2798 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002800 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002802 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002804 if (ioc->pci_irq != -1) {
2805 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302806 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002807 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002808 ioc->pci_irq = -1;
2809 }
2810
2811 if (ioc->memmap != NULL) {
2812 iounmap(ioc->memmap);
2813 ioc->memmap = NULL;
2814 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302816 pci_disable_device(ioc->pcidev);
2817 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2818
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002819 /* Zap the adapter lookup ptr! */
2820 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002822 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002823 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2824 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002825
2826 if (ioc->alt_ioc)
2827 ioc->alt_ioc->alt_ioc = NULL;
2828
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002829 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830}
2831
2832/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002833/**
2834 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 * @ioc: Pointer to MPT adapter structure
2836 */
2837static void
2838MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2839{
2840 int i = 0;
2841
2842 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302843 if (ioc->prod_name)
2844 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 printk("Capabilities={");
2846
2847 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2848 printk("Initiator");
2849 i++;
2850 }
2851
2852 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2853 printk("%sTarget", i ? "," : "");
2854 i++;
2855 }
2856
2857 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2858 printk("%sLAN", i ? "," : "");
2859 i++;
2860 }
2861
2862#if 0
2863 /*
2864 * This would probably evoke more questions than it's worth
2865 */
2866 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2867 printk("%sLogBusAddr", i ? "," : "");
2868 i++;
2869 }
2870#endif
2871
2872 printk("}\n");
2873}
2874
2875/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002876/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2878 * @ioc: Pointer to MPT_ADAPTER structure
2879 * @force: Force hard KickStart of IOC
2880 * @sleepFlag: Specifies whether the process can sleep
2881 *
2882 * Returns:
2883 * 1 - DIAG reset and READY
2884 * 0 - READY initially OR soft reset and READY
2885 * -1 - Any failure on KickStart
2886 * -2 - Msg Unit Reset Failed
2887 * -3 - IO Unit Reset Failed
2888 * -4 - IOC owned by a PEER
2889 */
2890static int
2891MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2892{
2893 u32 ioc_state;
2894 int statefault = 0;
2895 int cntdn;
2896 int hard_reset_done = 0;
2897 int r;
2898 int ii;
2899 int whoinit;
2900
2901 /* Get current [raw] IOC state */
2902 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002903 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904
2905 /*
2906 * Check to see if IOC got left/stuck in doorbell handshake
2907 * grip of death. If so, hard reset the IOC.
2908 */
2909 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2910 statefault = 1;
2911 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2912 ioc->name);
2913 }
2914
2915 /* Is it already READY? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302916 if (!statefault &&
2917 ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) {
2918 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2919 "IOC is in READY state\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 return 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302921 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922
2923 /*
2924 * Check to see if IOC is in FAULT state.
2925 */
2926 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2927 statefault = 2;
2928 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002929 ioc->name);
2930 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2931 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 }
2933
2934 /*
2935 * Hmmm... Did it get left operational?
2936 */
2937 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302938 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 ioc->name));
2940
2941 /* Check WhoInit.
2942 * If PCI Peer, exit.
2943 * Else, if no fault conditions are present, issue a MessageUnitReset
2944 * Else, fall through to KickStart case
2945 */
2946 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002947 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2948 "whoinit 0x%x statefault %d force %d\n",
2949 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 if (whoinit == MPI_WHOINIT_PCI_PEER)
2951 return -4;
2952 else {
2953 if ((statefault == 0 ) && (force == 0)) {
2954 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2955 return 0;
2956 }
2957 statefault = 3;
2958 }
2959 }
2960
2961 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2962 if (hard_reset_done < 0)
2963 return -1;
2964
2965 /*
2966 * Loop here waiting for IOC to come READY.
2967 */
2968 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002969 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970
2971 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2972 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2973 /*
2974 * BIOS or previous driver load left IOC in OP state.
2975 * Reset messaging FIFOs.
2976 */
2977 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2978 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2979 return -2;
2980 }
2981 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2982 /*
2983 * Something is wrong. Try to get IOC back
2984 * to a known state.
2985 */
2986 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2987 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2988 return -3;
2989 }
2990 }
2991
2992 ii++; cntdn--;
2993 if (!cntdn) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302994 printk(MYIOC_s_ERR_FMT
2995 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
2996 ioc->name, ioc_state, (int)((ii+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 return -ETIME;
2998 }
2999
3000 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003001 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 } else {
3003 mdelay (1); /* 1 msec delay */
3004 }
3005
3006 }
3007
3008 if (statefault < 3) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303009 printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name,
3010 statefault == 1 ? "stuck handshake" : "IOC FAULT");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 }
3012
3013 return hard_reset_done;
3014}
3015
3016/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003017/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 * mpt_GetIocState - Get the current state of a MPT adapter.
3019 * @ioc: Pointer to MPT_ADAPTER structure
3020 * @cooked: Request raw or cooked IOC state
3021 *
3022 * Returns all IOC Doorbell register bits if cooked==0, else just the
3023 * Doorbell bits in MPI_IOC_STATE_MASK.
3024 */
3025u32
3026mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
3027{
3028 u32 s, sc;
3029
3030 /* Get! */
3031 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032 sc = s & MPI_IOC_STATE_MASK;
3033
3034 /* Save! */
3035 ioc->last_state = sc;
3036
3037 return cooked ? sc : s;
3038}
3039
3040/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003041/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 * GetIocFacts - Send IOCFacts request to MPT adapter.
3043 * @ioc: Pointer to MPT_ADAPTER structure
3044 * @sleepFlag: Specifies whether the process can sleep
3045 * @reason: If recovery, only update facts.
3046 *
3047 * Returns 0 for success, non-zero for failure.
3048 */
3049static int
3050GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
3051{
3052 IOCFacts_t get_facts;
3053 IOCFactsReply_t *facts;
3054 int r;
3055 int req_sz;
3056 int reply_sz;
3057 int sz;
3058 u32 status, vv;
3059 u8 shiftFactor=1;
3060
3061 /* IOC *must* NOT be in RESET state! */
3062 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303063 printk(KERN_ERR MYNAM
3064 ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
3065 ioc->name, ioc->last_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 return -44;
3067 }
3068
3069 facts = &ioc->facts;
3070
3071 /* Destination (reply area)... */
3072 reply_sz = sizeof(*facts);
3073 memset(facts, 0, reply_sz);
3074
3075 /* Request area (get_facts on the stack right now!) */
3076 req_sz = sizeof(get_facts);
3077 memset(&get_facts, 0, req_sz);
3078
3079 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
3080 /* Assert: All other get_facts fields are zero! */
3081
Prakash, Sathya436ace72007-07-24 15:42:08 +05303082 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003083 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 ioc->name, req_sz, reply_sz));
3085
3086 /* No non-zero fields in the get_facts request are greater than
3087 * 1 byte in size, so we can just fire it off as is.
3088 */
3089 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3090 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3091 if (r != 0)
3092 return r;
3093
3094 /*
3095 * Now byte swap (GRRR) the necessary fields before any further
3096 * inspection of reply contents.
3097 *
3098 * But need to do some sanity checks on MsgLength (byte) field
3099 * to make sure we don't zero IOC's req_sz!
3100 */
3101 /* Did we get a valid reply? */
3102 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3103 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3104 /*
3105 * If not been here, done that, save off first WhoInit value
3106 */
3107 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3108 ioc->FirstWhoInit = facts->WhoInit;
3109 }
3110
3111 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3112 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3113 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3114 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3115 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003116 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 /* CHECKME! IOCStatus, IOCLogInfo */
3118
3119 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3120 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3121
3122 /*
3123 * FC f/w version changed between 1.1 and 1.2
3124 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3125 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3126 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303127 if (facts->MsgVersion < MPI_VERSION_01_02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 /*
3129 * Handle old FC f/w style, convert to new...
3130 */
3131 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3132 facts->FWVersion.Word =
3133 ((oldv<<12) & 0xFF000000) |
3134 ((oldv<<8) & 0x000FFF00);
3135 } else
3136 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3137
3138 facts->ProductID = le16_to_cpu(facts->ProductID);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303139
Eric Mooreb506ade2007-01-29 09:45:37 -07003140 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3141 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3142 ioc->ir_firmware = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303143
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 facts->CurrentHostMfaHighAddr =
3145 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3146 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3147 facts->CurrentSenseBufferHighAddr =
3148 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3149 facts->CurReplyFrameSize =
3150 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003151 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152
3153 /*
3154 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3155 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3156 * to 14 in MPI-1.01.0x.
3157 */
3158 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
Kashyap, Desai2f187862009-05-29 16:52:37 +05303159 facts->MsgVersion > MPI_VERSION_01_00) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3161 }
3162
Rasmus Villemoesf6e495a2014-07-01 14:56:20 +02003163 facts->FWImageSize = ALIGN(facts->FWImageSize, 4);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003164
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 if (!facts->RequestFrameSize) {
3166 /* Something is wrong! */
3167 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3168 ioc->name);
3169 return -55;
3170 }
3171
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003172 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 vv = ((63 / (sz * 4)) + 1) & 0x03;
3174 ioc->NB_for_64_byte_frame = vv;
3175 while ( sz )
3176 {
3177 shiftFactor++;
3178 sz = sz >> 1;
3179 }
3180 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303181 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003182 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3183 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003184
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3186 /*
3187 * Set values for this IOC's request & reply frame sizes,
3188 * and request & reply queue depths...
3189 */
3190 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3191 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3192 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3193 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3194
Prakash, Sathya436ace72007-07-24 15:42:08 +05303195 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303197 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198 ioc->name, ioc->req_sz, ioc->req_depth));
3199
3200 /* Get port facts! */
3201 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3202 return r;
3203 }
3204 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003205 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3207 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3208 RequestFrameSize)/sizeof(u32)));
3209 return -66;
3210 }
3211
3212 return 0;
3213}
3214
3215/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003216/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217 * GetPortFacts - Send PortFacts request to MPT adapter.
3218 * @ioc: Pointer to MPT_ADAPTER structure
3219 * @portnum: Port number
3220 * @sleepFlag: Specifies whether the process can sleep
3221 *
3222 * Returns 0 for success, non-zero for failure.
3223 */
3224static int
3225GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3226{
3227 PortFacts_t get_pfacts;
3228 PortFactsReply_t *pfacts;
3229 int ii;
3230 int req_sz;
3231 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003232 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233
3234 /* IOC *must* NOT be in RESET state! */
3235 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003236 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3237 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 return -4;
3239 }
3240
3241 pfacts = &ioc->pfacts[portnum];
3242
3243 /* Destination (reply area)... */
3244 reply_sz = sizeof(*pfacts);
3245 memset(pfacts, 0, reply_sz);
3246
3247 /* Request area (get_pfacts on the stack right now!) */
3248 req_sz = sizeof(get_pfacts);
3249 memset(&get_pfacts, 0, req_sz);
3250
3251 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3252 get_pfacts.PortNumber = portnum;
3253 /* Assert: All other get_pfacts fields are zero! */
3254
Prakash, Sathya436ace72007-07-24 15:42:08 +05303255 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 ioc->name, portnum));
3257
3258 /* No non-zero fields in the get_pfacts request are greater than
3259 * 1 byte in size, so we can just fire it off as is.
3260 */
3261 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3262 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3263 if (ii != 0)
3264 return ii;
3265
3266 /* Did we get a valid reply? */
3267
3268 /* Now byte swap the necessary fields in the response. */
3269 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3270 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3271 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3272 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3273 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3274 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3275 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3276 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3277 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3278
Eric Moore793955f2007-01-29 09:42:20 -07003279 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3280 pfacts->MaxDevices;
3281 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3282 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3283
3284 /*
3285 * Place all the devices on channels
3286 *
3287 * (for debuging)
3288 */
3289 if (mpt_channel_mapping) {
3290 ioc->devices_per_bus = 1;
3291 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3292 }
3293
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 return 0;
3295}
3296
3297/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003298/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 * SendIocInit - Send IOCInit request to MPT adapter.
3300 * @ioc: Pointer to MPT_ADAPTER structure
3301 * @sleepFlag: Specifies whether the process can sleep
3302 *
3303 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3304 *
3305 * Returns 0 for success, non-zero for failure.
3306 */
3307static int
3308SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3309{
3310 IOCInit_t ioc_init;
3311 MPIDefaultReply_t init_reply;
3312 u32 state;
3313 int r;
3314 int count;
3315 int cntdn;
3316
3317 memset(&ioc_init, 0, sizeof(ioc_init));
3318 memset(&init_reply, 0, sizeof(init_reply));
3319
3320 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3321 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3322
3323 /* If we are in a recovery mode and we uploaded the FW image,
3324 * then this pointer is not NULL. Skip the upload a second time.
3325 * Set this flag if cached_fw set for either IOC.
3326 */
3327 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3328 ioc->upload_fw = 1;
3329 else
3330 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303331 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3333
Eric Moore793955f2007-01-29 09:42:20 -07003334 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3335 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303336
Prakash, Sathya436ace72007-07-24 15:42:08 +05303337 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003338 ioc->name, ioc->facts.MsgVersion));
3339 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3340 // set MsgVersion and HeaderVersion host driver was built with
3341 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3342 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003344 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3345 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3346 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3347 return -99;
3348 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3350
Kashyap, Desai2f187862009-05-29 16:52:37 +05303351 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 /* Save the upper 32-bits of the request
3353 * (reply) and sense buffers.
3354 */
3355 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3356 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3357 } else {
3358 /* Force 32-bit addressing */
3359 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3360 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3361 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003362
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3364 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003365 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3366 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367
Prakash, Sathya436ace72007-07-24 15:42:08 +05303368 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 ioc->name, &ioc_init));
3370
3371 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3372 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003373 if (r != 0) {
3374 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377
3378 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003379 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 */
3381
Prakash, Sathya436ace72007-07-24 15:42:08 +05303382 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003384
3385 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3386 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389
3390 /* YIKES! SUPER IMPORTANT!!!
3391 * Poll IocState until _OPERATIONAL while IOC is doing
3392 * LoopInit and TargetDiscovery!
3393 */
3394 count = 0;
3395 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3396 state = mpt_GetIocState(ioc, 1);
3397 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3398 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003399 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 } else {
3401 mdelay(1);
3402 }
3403
3404 if (!cntdn) {
3405 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3406 ioc->name, (int)((count+5)/HZ));
3407 return -9;
3408 }
3409
3410 state = mpt_GetIocState(ioc, 1);
3411 count++;
3412 }
Eric Moore29dd3602007-09-14 18:46:51 -06003413 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 ioc->name, count));
3415
Eric Mooreba856d32006-07-11 17:34:01 -06003416 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 return r;
3418}
3419
3420/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003421/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 * SendPortEnable - Send PortEnable request to MPT adapter port.
3423 * @ioc: Pointer to MPT_ADAPTER structure
3424 * @portnum: Port number to enable
3425 * @sleepFlag: Specifies whether the process can sleep
3426 *
3427 * Send PortEnable to bring IOC to OPERATIONAL state.
3428 *
3429 * Returns 0 for success, non-zero for failure.
3430 */
3431static int
3432SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3433{
3434 PortEnable_t port_enable;
3435 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003436 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 int req_sz;
3438 int reply_sz;
3439
3440 /* Destination... */
3441 reply_sz = sizeof(MPIDefaultReply_t);
3442 memset(&reply_buf, 0, reply_sz);
3443
3444 req_sz = sizeof(PortEnable_t);
3445 memset(&port_enable, 0, req_sz);
3446
3447 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3448 port_enable.PortNumber = portnum;
3449/* port_enable.ChainOffset = 0; */
3450/* port_enable.MsgFlags = 0; */
3451/* port_enable.MsgContext = 0; */
3452
Prakash, Sathya436ace72007-07-24 15:42:08 +05303453 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 ioc->name, portnum, &port_enable));
3455
3456 /* RAID FW may take a long time to enable
3457 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003458 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003459 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3460 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3461 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003462 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003463 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3464 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3465 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003467 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468}
3469
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003470/**
3471 * mpt_alloc_fw_memory - allocate firmware memory
3472 * @ioc: Pointer to MPT_ADAPTER structure
3473 * @size: total FW bytes
3474 *
3475 * If memory has already been allocated, the same (cached) value
3476 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303477 *
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003478 * Return 0 if successful, or non-zero for failure
Prakash, Sathya984621b2008-01-11 14:42:17 +05303479 **/
3480int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3482{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303483 int rc;
3484
3485 if (ioc->cached_fw) {
3486 rc = 0; /* use already allocated memory */
3487 goto out;
3488 }
3489 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3491 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303492 rc = 0;
3493 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303495 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3496 if (!ioc->cached_fw) {
3497 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3498 ioc->name);
3499 rc = -1;
3500 } else {
3501 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3502 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3503 ioc->alloc_total += size;
3504 rc = 0;
3505 }
3506 out:
3507 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303509
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003510/**
3511 * mpt_free_fw_memory - free firmware memory
3512 * @ioc: Pointer to MPT_ADAPTER structure
3513 *
3514 * If alt_img is NULL, delete from ioc structure.
3515 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303516 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517void
3518mpt_free_fw_memory(MPT_ADAPTER *ioc)
3519{
3520 int sz;
3521
Prakash, Sathya984621b2008-01-11 14:42:17 +05303522 if (!ioc->cached_fw)
3523 return;
3524
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303526 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3527 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003528 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303529 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531}
3532
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003534/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3536 * @ioc: Pointer to MPT_ADAPTER structure
3537 * @sleepFlag: Specifies whether the process can sleep
3538 *
3539 * Returns 0 for success, >0 for handshake failure
3540 * <0 for fw upload failure.
3541 *
3542 * Remark: If bound IOC and a successful FWUpload was performed
3543 * on the bound IOC, the second image is discarded
3544 * and memory is free'd. Both channels must upload to prevent
3545 * IOC from running in degraded mode.
3546 */
3547static int
3548mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3549{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550 u8 reply[sizeof(FWUploadReply_t)];
3551 FWUpload_t *prequest;
3552 FWUploadReply_t *preply;
3553 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554 u32 flagsLength;
3555 int ii, sz, reply_sz;
3556 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303557 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558 /* If the image size is 0, we are done.
3559 */
3560 if ((sz = ioc->facts.FWImageSize) == 0)
3561 return 0;
3562
Prakash, Sathya984621b2008-01-11 14:42:17 +05303563 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3564 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565
Eric Moore29dd3602007-09-14 18:46:51 -06003566 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3567 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003568
Eric Moorebc6e0892007-09-29 10:16:28 -06003569 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3570 kzalloc(ioc->req_sz, GFP_KERNEL);
3571 if (!prequest) {
3572 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3573 "while allocating memory \n", ioc->name));
3574 mpt_free_fw_memory(ioc);
3575 return -ENOMEM;
3576 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577
Eric Moorebc6e0892007-09-29 10:16:28 -06003578 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579
3580 reply_sz = sizeof(reply);
3581 memset(preply, 0, reply_sz);
3582
3583 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3584 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3585
3586 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3587 ptcsge->DetailsLength = 12;
3588 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3589 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003590 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303593 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3594 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3595 ioc->SGE_size;
3596 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3597 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3598 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003599 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303601 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3602 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603
Kashyap, Desai2f187862009-05-29 16:52:37 +05303604 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
3605 "rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606
3607 cmdStatus = -EFAULT;
3608 if (ii == 0) {
3609 /* Handshake transfer was complete and successful.
3610 * Check the Reply Frame.
3611 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303612 int status;
3613 status = le16_to_cpu(preply->IOCStatus) &
3614 MPI_IOCSTATUS_MASK;
3615 if (status == MPI_IOCSTATUS_SUCCESS &&
3616 ioc->facts.FWImageSize ==
3617 le32_to_cpu(preply->ActualImageSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 cmdStatus = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303620 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 ioc->name, cmdStatus));
3622
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003623
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 if (cmdStatus) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303625 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
3626 "freeing image \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627 mpt_free_fw_memory(ioc);
3628 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003629 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630
3631 return cmdStatus;
3632}
3633
3634/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003635/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 * mpt_downloadboot - DownloadBoot code
3637 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003638 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 * @sleepFlag: Specifies whether the process can sleep
3640 *
3641 * FwDownloadBoot requires Programmed IO access.
3642 *
3643 * Returns 0 for success
3644 * -1 FW Image size is 0
3645 * -2 No valid cached_fw Pointer
3646 * <0 for fw upload failure.
3647 */
3648static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003649mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 MpiExtImageHeader_t *pExtImage;
3652 u32 fwSize;
3653 u32 diag0val;
3654 int count;
3655 u32 *ptrFw;
3656 u32 diagRwData;
3657 u32 nextImage;
3658 u32 load_addr;
3659 u32 ioc_state=0;
3660
Prakash, Sathya436ace72007-07-24 15:42:08 +05303661 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003662 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003663
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3665 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3666 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3667 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3668 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3669 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3670
3671 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3672
3673 /* wait 1 msec */
3674 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003675 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 } else {
3677 mdelay (1);
3678 }
3679
3680 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3681 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3682
3683 for (count = 0; count < 30; count ++) {
3684 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3685 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303686 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 ioc->name, count));
3688 break;
3689 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003690 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003692 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003694 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 }
3696 }
3697
3698 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303699 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003700 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 ioc->name, diag0val));
3702 return -3;
3703 }
3704
3705 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3706 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3707 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3708 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3709 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3710 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3711
3712 /* Set the DiagRwEn and Disable ARM bits */
3713 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3714
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 fwSize = (pFwHeader->ImageSize + 3)/4;
3716 ptrFw = (u32 *) pFwHeader;
3717
3718 /* Write the LoadStartAddress to the DiagRw Address Register
3719 * using Programmed IO
3720 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003721 if (ioc->errata_flag_1064)
3722 pci_enable_io_access(ioc->pcidev);
3723
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303725 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726 ioc->name, pFwHeader->LoadStartAddress));
3727
Prakash, Sathya436ace72007-07-24 15:42:08 +05303728 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729 ioc->name, fwSize*4, ptrFw));
3730 while (fwSize--) {
3731 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3732 }
3733
3734 nextImage = pFwHeader->NextImageHeaderOffset;
3735 while (nextImage) {
3736 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3737
3738 load_addr = pExtImage->LoadStartAddress;
3739
3740 fwSize = (pExtImage->ImageSize + 3) >> 2;
3741 ptrFw = (u32 *)pExtImage;
3742
Prakash, Sathya436ace72007-07-24 15:42:08 +05303743 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 +02003744 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3746
3747 while (fwSize--) {
3748 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3749 }
3750 nextImage = pExtImage->NextImageHeaderOffset;
3751 }
3752
3753 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303754 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3756
3757 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303758 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3760
3761 /* Clear the internal flash bad bit - autoincrementing register,
3762 * so must do two writes.
3763 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003764 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003765 /*
3766 * 1030 and 1035 H/W errata, workaround to access
3767 * the ClearFlashBadSignatureBit
3768 */
3769 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3770 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3771 diagRwData |= 0x40000000;
3772 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3773 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3774
3775 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3776 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3777 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3778 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3779
3780 /* wait 1 msec */
3781 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003782 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003783 } else {
3784 mdelay (1);
3785 }
3786 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003788 if (ioc->errata_flag_1064)
3789 pci_disable_io_access(ioc->pcidev);
3790
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303792 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003793 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003795 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303796 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797 ioc->name, diag0val));
3798 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3799
3800 /* Write 0xFF to reset the sequencer */
3801 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3802
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003803 if (ioc->bus_type == SAS) {
3804 ioc_state = mpt_GetIocState(ioc, 0);
3805 if ( (GetIocFacts(ioc, sleepFlag,
3806 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303807 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003808 ioc->name, ioc_state));
3809 return -EFAULT;
3810 }
3811 }
3812
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813 for (count=0; count<HZ*20; count++) {
3814 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303815 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3816 "downloadboot successful! (count=%d) IocState=%x\n",
3817 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003818 if (ioc->bus_type == SAS) {
3819 return 0;
3820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303822 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3823 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 ioc->name));
3825 return -EFAULT;
3826 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303827 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3828 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 ioc->name));
3830 return 0;
3831 }
3832 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003833 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834 } else {
3835 mdelay (10);
3836 }
3837 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303838 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3839 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 return -EFAULT;
3841}
3842
3843/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003844/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 * KickStart - Perform hard reset of MPT adapter.
3846 * @ioc: Pointer to MPT_ADAPTER structure
3847 * @force: Force hard reset
3848 * @sleepFlag: Specifies whether the process can sleep
3849 *
3850 * This routine places MPT adapter in diagnostic mode via the
3851 * WriteSequence register, and then performs a hard reset of adapter
3852 * via the Diagnostic register.
3853 *
3854 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3855 * or NO_SLEEP (interrupt thread, use mdelay)
3856 * force - 1 if doorbell active, board fault state
3857 * board operational, IOC_RECOVERY or
3858 * IOC_BRINGUP and there is an alt_ioc.
3859 * 0 else
3860 *
3861 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003862 * 1 - hard reset, READY
3863 * 0 - no reset due to History bit, READY
3864 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 * OR reset but failed to come READY
3866 * -2 - no reset, could not enter DIAG mode
3867 * -3 - reset but bad FW bit
3868 */
3869static int
3870KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3871{
3872 int hard_reset_done = 0;
3873 u32 ioc_state=0;
3874 int cnt,cntdn;
3875
Eric Moore29dd3602007-09-14 18:46:51 -06003876 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003877 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 /* Always issue a Msg Unit Reset first. This will clear some
3879 * SCSI bus hang conditions.
3880 */
3881 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3882
3883 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003884 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885 } else {
3886 mdelay (1000);
3887 }
3888 }
3889
3890 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3891 if (hard_reset_done < 0)
3892 return hard_reset_done;
3893
Prakash, Sathya436ace72007-07-24 15:42:08 +05303894 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003895 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896
3897 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3898 for (cnt=0; cnt<cntdn; cnt++) {
3899 ioc_state = mpt_GetIocState(ioc, 1);
3900 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303901 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 ioc->name, cnt));
3903 return hard_reset_done;
3904 }
3905 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003906 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 } else {
3908 mdelay (10);
3909 }
3910 }
3911
Eric Moore29dd3602007-09-14 18:46:51 -06003912 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3913 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 return -1;
3915}
3916
3917/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003918/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919 * mpt_diag_reset - Perform hard reset of the adapter.
3920 * @ioc: Pointer to MPT_ADAPTER structure
3921 * @ignore: Set if to honor and clear to ignore
3922 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003923 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 * else set to NO_SLEEP (use mdelay instead)
3925 *
3926 * This routine places the adapter in diagnostic mode via the
3927 * WriteSequence register and then performs a hard reset of adapter
3928 * via the Diagnostic register. Adapter should be in ready state
3929 * upon successful completion.
3930 *
3931 * Returns: 1 hard reset successful
3932 * 0 no reset performed because reset history bit set
3933 * -2 enabling diagnostic mode failed
3934 * -3 diagnostic reset failed
3935 */
3936static int
3937mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3938{
3939 u32 diag0val;
3940 u32 doorbell;
3941 int hard_reset_done = 0;
3942 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003943 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303944 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Kashyap, Desaid1306912009-08-05 12:53:51 +05303945 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003946
Eric Moorecd2c6192007-01-29 09:47:47 -07003947 /* Clear any existing interrupts */
3948 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3949
Eric Moore87cf8982006-06-27 16:09:26 -06003950 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303951
3952 if (!ignore)
3953 return 0;
3954
Prakash, Sathya436ace72007-07-24 15:42:08 +05303955 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003956 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003957 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3958 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3959 if (sleepFlag == CAN_SLEEP)
3960 msleep(1);
3961 else
3962 mdelay(1);
3963
Kashyap, Desaid1306912009-08-05 12:53:51 +05303964 /*
3965 * Call each currently registered protocol IOC reset handler
3966 * with pre-reset indication.
3967 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3968 * MptResetHandlers[] registered yet.
3969 */
3970 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3971 if (MptResetHandlers[cb_idx])
3972 (*(MptResetHandlers[cb_idx]))(ioc,
3973 MPT_IOC_PRE_RESET);
3974 }
3975
Eric Moore87cf8982006-06-27 16:09:26 -06003976 for (count = 0; count < 60; count ++) {
3977 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3978 doorbell &= MPI_IOC_STATE_MASK;
3979
Prakash, Sathya436ace72007-07-24 15:42:08 +05303980 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003981 "looking for READY STATE: doorbell=%x"
3982 " count=%d\n",
3983 ioc->name, doorbell, count));
Kashyap, Desai2f187862009-05-29 16:52:37 +05303984
Eric Moore87cf8982006-06-27 16:09:26 -06003985 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003986 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003987 }
3988
3989 /* wait 1 sec */
3990 if (sleepFlag == CAN_SLEEP)
3991 msleep(1000);
3992 else
3993 mdelay(1000);
3994 }
3995 return -1;
3996 }
3997
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 /* Use "Diagnostic reset" method! (only thing available!) */
3999 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4000
Prakash, Sathya436ace72007-07-24 15:42:08 +05304001 if (ioc->debug_level & MPT_DEBUG) {
4002 if (ioc->alt_ioc)
4003 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4004 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304006 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007
4008 /* Do the reset if we are told to ignore the reset history
4009 * or if the reset history is 0
4010 */
4011 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
4012 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4013 /* Write magic sequence to WriteSequence register
4014 * Loop until in diagnostic mode
4015 */
4016 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4017 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4018 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4019 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4020 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4021 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4022
4023 /* wait 100 msec */
4024 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004025 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 } else {
4027 mdelay (100);
4028 }
4029
4030 count++;
4031 if (count > 20) {
4032 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4033 ioc->name, diag0val);
4034 return -2;
4035
4036 }
4037
4038 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4039
Prakash, Sathya436ace72007-07-24 15:42:08 +05304040 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 ioc->name, diag0val));
4042 }
4043
Prakash, Sathya436ace72007-07-24 15:42:08 +05304044 if (ioc->debug_level & MPT_DEBUG) {
4045 if (ioc->alt_ioc)
4046 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4047 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304049 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 /*
4051 * Disable the ARM (Bug fix)
4052 *
4053 */
4054 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004055 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056
4057 /*
4058 * Now hit the reset bit in the Diagnostic register
4059 * (THE BIG HAMMER!) (Clears DRWE bit).
4060 */
4061 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
4062 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304063 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004064 ioc->name));
4065
4066 /*
4067 * Call each currently registered protocol IOC reset handler
4068 * with pre-reset indication.
4069 * NOTE: If we're doing _IOC_BRINGUP, there can be no
4070 * MptResetHandlers[] registered yet.
4071 */
Kashyap, Desaid1306912009-08-05 12:53:51 +05304072 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
4073 if (MptResetHandlers[cb_idx]) {
4074 mpt_signal_reset(cb_idx,
4075 ioc, MPT_IOC_PRE_RESET);
4076 if (ioc->alt_ioc) {
4077 mpt_signal_reset(cb_idx,
4078 ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079 }
4080 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081 }
4082
Eric Moore0ccdb002006-07-11 17:33:13 -06004083 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304084 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06004085 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304086 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4087 else
4088 cached_fw = NULL;
4089 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090 /* If the DownloadBoot operation fails, the
4091 * IOC will be left unusable. This is a fatal error
4092 * case. _diag_reset will return < 0
4093 */
4094 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304095 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4097 break;
4098 }
4099
Prakash, Sathya436ace72007-07-24 15:42:08 +05304100 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304101 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102 /* wait 1 sec */
4103 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004104 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105 } else {
4106 mdelay (1000);
4107 }
4108 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304109 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004110 printk(MYIOC_s_WARN_FMT
4111 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112 }
4113
4114 } else {
4115 /* Wait for FW to reload and for board
4116 * to go to the READY state.
4117 * Maximum wait is 60 seconds.
4118 * If fail, no error will check again
4119 * with calling program.
4120 */
4121 for (count = 0; count < 60; count ++) {
4122 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4123 doorbell &= MPI_IOC_STATE_MASK;
4124
Kashyap, Desai2f187862009-05-29 16:52:37 +05304125 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4126 "looking for READY STATE: doorbell=%x"
4127 " count=%d\n", ioc->name, doorbell, count));
4128
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129 if (doorbell == MPI_IOC_STATE_READY) {
4130 break;
4131 }
4132
4133 /* wait 1 sec */
4134 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004135 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136 } else {
4137 mdelay (1000);
4138 }
4139 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05304140
4141 if (doorbell != MPI_IOC_STATE_READY)
4142 printk(MYIOC_s_ERR_FMT "Failed to come READY "
4143 "after reset! IocState=%x", ioc->name,
4144 doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 }
4146 }
4147
4148 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304149 if (ioc->debug_level & MPT_DEBUG) {
4150 if (ioc->alt_ioc)
4151 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4152 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4153 ioc->name, diag0val, diag1val));
4154 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004155
4156 /* Clear RESET_HISTORY bit! Place board in the
4157 * diagnostic mode to update the diag register.
4158 */
4159 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4160 count = 0;
4161 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4162 /* Write magic sequence to WriteSequence register
4163 * Loop until in diagnostic mode
4164 */
4165 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4166 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4167 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4168 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4169 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4170 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4171
4172 /* wait 100 msec */
4173 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004174 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175 } else {
4176 mdelay (100);
4177 }
4178
4179 count++;
4180 if (count > 20) {
4181 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4182 ioc->name, diag0val);
4183 break;
4184 }
4185 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4186 }
4187 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4188 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4189 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4190 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4191 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4192 ioc->name);
4193 }
4194
4195 /* Disable Diagnostic Mode
4196 */
4197 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4198
4199 /* Check FW reload status flags.
4200 */
4201 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4202 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4203 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4204 ioc->name, diag0val);
4205 return -3;
4206 }
4207
Prakash, Sathya436ace72007-07-24 15:42:08 +05304208 if (ioc->debug_level & MPT_DEBUG) {
4209 if (ioc->alt_ioc)
4210 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4211 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304213 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214
4215 /*
4216 * Reset flag that says we've enabled event notification
4217 */
4218 ioc->facts.EventState = 0;
4219
4220 if (ioc->alt_ioc)
4221 ioc->alt_ioc->facts.EventState = 0;
4222
4223 return hard_reset_done;
4224}
4225
4226/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004227/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 * SendIocReset - Send IOCReset request to MPT adapter.
4229 * @ioc: Pointer to MPT_ADAPTER structure
4230 * @reset_type: reset type, expected values are
4231 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004232 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 *
4234 * Send IOCReset request to the MPT adapter.
4235 *
4236 * Returns 0 for success, non-zero for failure.
4237 */
4238static int
4239SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4240{
4241 int r;
4242 u32 state;
4243 int cntdn, count;
4244
Prakash, Sathya436ace72007-07-24 15:42:08 +05304245 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246 ioc->name, reset_type));
4247 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4248 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4249 return r;
4250
4251 /* FW ACK'd request, wait for READY state
4252 */
4253 count = 0;
4254 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4255
4256 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4257 cntdn--;
4258 count++;
4259 if (!cntdn) {
4260 if (sleepFlag != CAN_SLEEP)
4261 count *= 10;
4262
Kashyap, Desai2f187862009-05-29 16:52:37 +05304263 printk(MYIOC_s_ERR_FMT
4264 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
4265 ioc->name, state, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266 return -ETIME;
4267 }
4268
4269 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004270 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271 } else {
4272 mdelay (1); /* 1 msec delay */
4273 }
4274 }
4275
4276 /* TODO!
4277 * Cleanup all event stuff for this IOC; re-issue EventNotification
4278 * request if needed.
4279 */
4280 if (ioc->facts.Function)
4281 ioc->facts.EventState = 0;
4282
4283 return 0;
4284}
4285
4286/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004287/**
4288 * initChainBuffers - Allocate memory for and initialize chain buffers
4289 * @ioc: Pointer to MPT_ADAPTER structure
4290 *
4291 * Allocates memory for and initializes chain buffers,
4292 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293 */
4294static int
4295initChainBuffers(MPT_ADAPTER *ioc)
4296{
4297 u8 *mem;
4298 int sz, ii, num_chain;
4299 int scale, num_sge, numSGE;
4300
4301 /* ReqToChain size must equal the req_depth
4302 * index = req_idx
4303 */
4304 if (ioc->ReqToChain == NULL) {
4305 sz = ioc->req_depth * sizeof(int);
4306 mem = kmalloc(sz, GFP_ATOMIC);
4307 if (mem == NULL)
4308 return -1;
4309
4310 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304311 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312 ioc->name, mem, sz));
4313 mem = kmalloc(sz, GFP_ATOMIC);
4314 if (mem == NULL)
4315 return -1;
4316
4317 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304318 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319 ioc->name, mem, sz));
4320 }
4321 for (ii = 0; ii < ioc->req_depth; ii++) {
4322 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4323 }
4324
4325 /* ChainToChain size must equal the total number
4326 * of chain buffers to be allocated.
4327 * index = chain_idx
4328 *
4329 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004330 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331 *
4332 * num_sge = num sge in request frame + last chain buffer
4333 * scale = num sge per chain buffer if no chain element
4334 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304335 scale = ioc->req_sz / ioc->SGE_size;
4336 if (ioc->sg_addr_size == sizeof(u64))
4337 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304339 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304341 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304343 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304345 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4346 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304348 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 ioc->name, num_sge, numSGE));
4350
Kashyap, Desai2f187862009-05-29 16:52:37 +05304351 if (ioc->bus_type == FC) {
4352 if (numSGE > MPT_SCSI_FC_SG_DEPTH)
4353 numSGE = MPT_SCSI_FC_SG_DEPTH;
4354 } else {
4355 if (numSGE > MPT_SCSI_SG_DEPTH)
4356 numSGE = MPT_SCSI_SG_DEPTH;
4357 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358
4359 num_chain = 1;
4360 while (numSGE - num_sge > 0) {
4361 num_chain++;
4362 num_sge += (scale - 1);
4363 }
4364 num_chain++;
4365
Prakash, Sathya436ace72007-07-24 15:42:08 +05304366 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 ioc->name, numSGE, num_sge, num_chain));
4368
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004369 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370 num_chain *= MPT_SCSI_CAN_QUEUE;
Anatolij Gustschinf1053a72009-12-12 14:52:21 +01004371 else if (ioc->bus_type == SAS)
4372 num_chain *= MPT_SAS_CAN_QUEUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373 else
4374 num_chain *= MPT_FC_CAN_QUEUE;
4375
4376 ioc->num_chain = num_chain;
4377
4378 sz = num_chain * sizeof(int);
4379 if (ioc->ChainToChain == NULL) {
4380 mem = kmalloc(sz, GFP_ATOMIC);
4381 if (mem == NULL)
4382 return -1;
4383
4384 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304385 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 ioc->name, mem, sz));
4387 } else {
4388 mem = (u8 *) ioc->ChainToChain;
4389 }
4390 memset(mem, 0xFF, sz);
4391 return num_chain;
4392}
4393
4394/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004395/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4397 * @ioc: Pointer to MPT_ADAPTER structure
4398 *
4399 * This routine allocates memory for the MPT reply and request frame
4400 * pools (if necessary), and primes the IOC reply FIFO with
4401 * reply frames.
4402 *
4403 * Returns 0 for success, non-zero for failure.
4404 */
4405static int
4406PrimeIocFifos(MPT_ADAPTER *ioc)
4407{
4408 MPT_FRAME_HDR *mf;
4409 unsigned long flags;
4410 dma_addr_t alloc_dma;
4411 u8 *mem;
4412 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304413 u64 dma_mask;
4414
4415 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416
4417 /* Prime reply FIFO... */
4418
4419 if (ioc->reply_frames == NULL) {
4420 if ( (num_chain = initChainBuffers(ioc)) < 0)
4421 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304422 /*
4423 * 1078 errata workaround for the 36GB limitation
4424 */
4425 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
Andrew Morton8e20ce92009-06-18 16:49:17 -07004426 ioc->dma_mask > DMA_BIT_MASK(35)) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304427 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4428 && !pci_set_consistent_dma_mask(ioc->pcidev,
4429 DMA_BIT_MASK(32))) {
Andrew Morton8e20ce92009-06-18 16:49:17 -07004430 dma_mask = DMA_BIT_MASK(35);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304431 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4432 "setting 35 bit addressing for "
4433 "Request/Reply/Chain and Sense Buffers\n",
4434 ioc->name));
4435 } else {
4436 /*Reseting DMA mask to 64 bit*/
4437 pci_set_dma_mask(ioc->pcidev,
4438 DMA_BIT_MASK(64));
4439 pci_set_consistent_dma_mask(ioc->pcidev,
4440 DMA_BIT_MASK(64));
4441
4442 printk(MYIOC_s_ERR_FMT
4443 "failed setting 35 bit addressing for "
4444 "Request/Reply/Chain and Sense Buffers\n",
4445 ioc->name);
4446 return -1;
4447 }
4448 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449
4450 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304451 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304453 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454 ioc->name, reply_sz, reply_sz));
4455
4456 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304457 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304459 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 ioc->name, sz, sz));
4461 total_size += sz;
4462
4463 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304464 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304466 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467 ioc->name, sz, sz, num_chain));
4468
4469 total_size += sz;
4470 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4471 if (mem == NULL) {
4472 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4473 ioc->name);
4474 goto out_fail;
4475 }
4476
Prakash, Sathya436ace72007-07-24 15:42:08 +05304477 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4479
4480 memset(mem, 0, total_size);
4481 ioc->alloc_total += total_size;
4482 ioc->alloc = mem;
4483 ioc->alloc_dma = alloc_dma;
4484 ioc->alloc_sz = total_size;
4485 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4486 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4487
Prakash, Sathya436ace72007-07-24 15:42:08 +05304488 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004489 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4490
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 alloc_dma += reply_sz;
4492 mem += reply_sz;
4493
4494 /* Request FIFO - WE manage this! */
4495
4496 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4497 ioc->req_frames_dma = alloc_dma;
4498
Prakash, Sathya436ace72007-07-24 15:42:08 +05304499 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500 ioc->name, mem, (void *)(ulong)alloc_dma));
4501
4502 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4503
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 for (i = 0; i < ioc->req_depth; i++) {
4505 alloc_dma += ioc->req_sz;
4506 mem += ioc->req_sz;
4507 }
4508
4509 ioc->ChainBuffer = mem;
4510 ioc->ChainBufferDMA = alloc_dma;
4511
Prakash, Sathya436ace72007-07-24 15:42:08 +05304512 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4514
4515 /* Initialize the free chain Q.
4516 */
4517
4518 INIT_LIST_HEAD(&ioc->FreeChainQ);
4519
4520 /* Post the chain buffers to the FreeChainQ.
4521 */
4522 mem = (u8 *)ioc->ChainBuffer;
4523 for (i=0; i < num_chain; i++) {
4524 mf = (MPT_FRAME_HDR *) mem;
4525 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4526 mem += ioc->req_sz;
4527 }
4528
4529 /* Initialize Request frames linked list
4530 */
4531 alloc_dma = ioc->req_frames_dma;
4532 mem = (u8 *) ioc->req_frames;
4533
4534 spin_lock_irqsave(&ioc->FreeQlock, flags);
4535 INIT_LIST_HEAD(&ioc->FreeQ);
4536 for (i = 0; i < ioc->req_depth; i++) {
4537 mf = (MPT_FRAME_HDR *) mem;
4538
4539 /* Queue REQUESTs *internally*! */
4540 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4541
4542 mem += ioc->req_sz;
4543 }
4544 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4545
4546 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4547 ioc->sense_buf_pool =
4548 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4549 if (ioc->sense_buf_pool == NULL) {
4550 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4551 ioc->name);
4552 goto out_fail;
4553 }
4554
4555 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4556 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304557 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4559
4560 }
4561
4562 /* Post Reply frames to FIFO
4563 */
4564 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304565 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4567
4568 for (i = 0; i < ioc->reply_depth; i++) {
4569 /* Write each address to the IOC! */
4570 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4571 alloc_dma += ioc->reply_sz;
4572 }
4573
Andrew Morton8e20ce92009-06-18 16:49:17 -07004574 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304575 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4576 ioc->dma_mask))
4577 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4578 "restoring 64 bit addressing\n", ioc->name));
4579
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580 return 0;
4581
4582out_fail:
Kashyap, Desai2f187862009-05-29 16:52:37 +05304583
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 if (ioc->alloc != NULL) {
4585 sz = ioc->alloc_sz;
4586 pci_free_consistent(ioc->pcidev,
4587 sz,
4588 ioc->alloc, ioc->alloc_dma);
4589 ioc->reply_frames = NULL;
4590 ioc->req_frames = NULL;
4591 ioc->alloc_total -= sz;
4592 }
4593 if (ioc->sense_buf_pool != NULL) {
4594 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4595 pci_free_consistent(ioc->pcidev,
4596 sz,
4597 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4598 ioc->sense_buf_pool = NULL;
4599 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304600
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 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4603 DMA_BIT_MASK(64)))
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 -1;
4608}
4609
4610/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4611/**
4612 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4613 * from IOC via doorbell handshake method.
4614 * @ioc: Pointer to MPT_ADAPTER structure
4615 * @reqBytes: Size of the request in bytes
4616 * @req: Pointer to MPT request frame
4617 * @replyBytes: Expected size of the reply in bytes
4618 * @u16reply: Pointer to area where reply should be written
4619 * @maxwait: Max wait time for a reply (in seconds)
4620 * @sleepFlag: Specifies whether the process can sleep
4621 *
4622 * NOTES: It is the callers responsibility to byte-swap fields in the
4623 * request which are greater than 1 byte in size. It is also the
4624 * callers responsibility to byte-swap response fields which are
4625 * greater than 1 byte in size.
4626 *
4627 * Returns 0 for success, non-zero for failure.
4628 */
4629static int
4630mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004631 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632{
4633 MPIDefaultReply_t *mptReply;
4634 int failcnt = 0;
4635 int t;
4636
4637 /*
4638 * Get ready to cache a handshake reply
4639 */
4640 ioc->hs_reply_idx = 0;
4641 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4642 mptReply->MsgLength = 0;
4643
4644 /*
4645 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4646 * then tell IOC that we want to handshake a request of N words.
4647 * (WRITE u32val to Doorbell reg).
4648 */
4649 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4650 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4651 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4652 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4653
4654 /*
4655 * Wait for IOC's doorbell handshake int
4656 */
4657 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4658 failcnt++;
4659
Prakash, Sathya436ace72007-07-24 15:42:08 +05304660 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4662
4663 /* Read doorbell and check for active bit */
4664 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4665 return -1;
4666
4667 /*
4668 * Clear doorbell int (WRITE 0 to IntStatus reg),
4669 * then wait for IOC to ACKnowledge that it's ready for
4670 * our handshake request.
4671 */
4672 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4673 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4674 failcnt++;
4675
4676 if (!failcnt) {
4677 int ii;
4678 u8 *req_as_bytes = (u8 *) req;
4679
4680 /*
4681 * Stuff request words via doorbell handshake,
4682 * with ACK from IOC for each.
4683 */
4684 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4685 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4686 (req_as_bytes[(ii*4) + 1] << 8) |
4687 (req_as_bytes[(ii*4) + 2] << 16) |
4688 (req_as_bytes[(ii*4) + 3] << 24));
4689
4690 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4691 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4692 failcnt++;
4693 }
4694
Prakash, Sathya436ace72007-07-24 15:42:08 +05304695 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004696 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697
Prakash, Sathya436ace72007-07-24 15:42:08 +05304698 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4700
4701 /*
4702 * Wait for completion of doorbell handshake reply from the IOC
4703 */
4704 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4705 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004706
Prakash, Sathya436ace72007-07-24 15:42:08 +05304707 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4709
4710 /*
4711 * Copy out the cached reply...
4712 */
4713 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4714 u16reply[ii] = ioc->hs_reply[ii];
4715 } else {
4716 return -99;
4717 }
4718
4719 return -failcnt;
4720}
4721
4722/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004723/**
4724 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725 * @ioc: Pointer to MPT_ADAPTER structure
4726 * @howlong: How long to wait (in seconds)
4727 * @sleepFlag: Specifies whether the process can sleep
4728 *
4729 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004730 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4731 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 *
4733 * Returns a negative value on failure, else wait loop count.
4734 */
4735static int
4736WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4737{
4738 int cntdn;
4739 int count = 0;
4740 u32 intstat=0;
4741
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004742 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743
4744 if (sleepFlag == CAN_SLEEP) {
4745 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004746 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4748 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4749 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750 count++;
4751 }
4752 } else {
4753 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004754 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4756 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4757 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 count++;
4759 }
4760 }
4761
4762 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304763 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764 ioc->name, count));
4765 return count;
4766 }
4767
4768 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4769 ioc->name, count, intstat);
4770 return -1;
4771}
4772
4773/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004774/**
4775 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 * @ioc: Pointer to MPT_ADAPTER structure
4777 * @howlong: How long to wait (in seconds)
4778 * @sleepFlag: Specifies whether the process can sleep
4779 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004780 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4781 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 *
4783 * Returns a negative value on failure, else wait loop count.
4784 */
4785static int
4786WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4787{
4788 int cntdn;
4789 int count = 0;
4790 u32 intstat=0;
4791
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004792 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 if (sleepFlag == CAN_SLEEP) {
4794 while (--cntdn) {
4795 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4796 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4797 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004798 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799 count++;
4800 }
4801 } else {
4802 while (--cntdn) {
4803 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4804 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4805 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004806 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 count++;
4808 }
4809 }
4810
4811 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304812 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813 ioc->name, count, howlong));
4814 return count;
4815 }
4816
4817 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4818 ioc->name, count, intstat);
4819 return -1;
4820}
4821
4822/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004823/**
4824 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825 * @ioc: Pointer to MPT_ADAPTER structure
4826 * @howlong: How long to wait (in seconds)
4827 * @sleepFlag: Specifies whether the process can sleep
4828 *
4829 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4830 * Reply is cached to IOC private area large enough to hold a maximum
4831 * of 128 bytes of reply data.
4832 *
4833 * Returns a negative value on failure, else size of reply in WORDS.
4834 */
4835static int
4836WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4837{
4838 int u16cnt = 0;
4839 int failcnt = 0;
4840 int t;
4841 u16 *hs_reply = ioc->hs_reply;
4842 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4843 u16 hword;
4844
4845 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4846
4847 /*
4848 * Get first two u16's so we can look at IOC's intended reply MsgLength
4849 */
4850 u16cnt=0;
4851 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4852 failcnt++;
4853 } else {
4854 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4855 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4856 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4857 failcnt++;
4858 else {
4859 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4860 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4861 }
4862 }
4863
Prakash, Sathya436ace72007-07-24 15:42:08 +05304864 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004865 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4867
4868 /*
4869 * If no error (and IOC said MsgLength is > 0), piece together
4870 * reply 16 bits at a time.
4871 */
4872 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4873 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4874 failcnt++;
4875 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4876 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004877 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 hs_reply[u16cnt] = hword;
4879 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4880 }
4881
4882 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4883 failcnt++;
4884 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4885
4886 if (failcnt) {
4887 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4888 ioc->name);
4889 return -failcnt;
4890 }
4891#if 0
4892 else if (u16cnt != (2 * mptReply->MsgLength)) {
4893 return -101;
4894 }
4895 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4896 return -102;
4897 }
4898#endif
4899
Prakash, Sathya436ace72007-07-24 15:42:08 +05304900 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004901 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902
Prakash, Sathya436ace72007-07-24 15:42:08 +05304903 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904 ioc->name, t, u16cnt/2));
4905 return u16cnt/2;
4906}
4907
4908/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004909/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910 * GetLanConfigPages - Fetch LANConfig pages.
4911 * @ioc: Pointer to MPT_ADAPTER structure
4912 *
4913 * Return: 0 for success
4914 * -ENOMEM if no memory available
4915 * -EPERM if not allowed due to ISR context
4916 * -EAGAIN if no msg frames currently available
4917 * -EFAULT for non-successful reply or no reply (timeout)
4918 */
4919static int
4920GetLanConfigPages(MPT_ADAPTER *ioc)
4921{
4922 ConfigPageHeader_t hdr;
4923 CONFIGPARMS cfg;
4924 LANPage0_t *ppage0_alloc;
4925 dma_addr_t page0_dma;
4926 LANPage1_t *ppage1_alloc;
4927 dma_addr_t page1_dma;
4928 int rc = 0;
4929 int data_sz;
4930 int copy_sz;
4931
4932 /* Get LAN Page 0 header */
4933 hdr.PageVersion = 0;
4934 hdr.PageLength = 0;
4935 hdr.PageNumber = 0;
4936 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004937 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004938 cfg.physAddr = -1;
4939 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4940 cfg.dir = 0;
4941 cfg.pageAddr = 0;
4942 cfg.timeout = 0;
4943
4944 if ((rc = mpt_config(ioc, &cfg)) != 0)
4945 return rc;
4946
4947 if (hdr.PageLength > 0) {
4948 data_sz = hdr.PageLength * 4;
4949 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4950 rc = -ENOMEM;
4951 if (ppage0_alloc) {
4952 memset((u8 *)ppage0_alloc, 0, data_sz);
4953 cfg.physAddr = page0_dma;
4954 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4955
4956 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4957 /* save the data */
4958 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4959 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4960
4961 }
4962
4963 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4964
4965 /* FIXME!
4966 * Normalize endianness of structure data,
4967 * by byte-swapping all > 1 byte fields!
4968 */
4969
4970 }
4971
4972 if (rc)
4973 return rc;
4974 }
4975
4976 /* Get LAN Page 1 header */
4977 hdr.PageVersion = 0;
4978 hdr.PageLength = 0;
4979 hdr.PageNumber = 1;
4980 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004981 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004982 cfg.physAddr = -1;
4983 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4984 cfg.dir = 0;
4985 cfg.pageAddr = 0;
4986
4987 if ((rc = mpt_config(ioc, &cfg)) != 0)
4988 return rc;
4989
4990 if (hdr.PageLength == 0)
4991 return 0;
4992
4993 data_sz = hdr.PageLength * 4;
4994 rc = -ENOMEM;
4995 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4996 if (ppage1_alloc) {
4997 memset((u8 *)ppage1_alloc, 0, data_sz);
4998 cfg.physAddr = page1_dma;
4999 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5000
5001 if ((rc = mpt_config(ioc, &cfg)) == 0) {
5002 /* save the data */
5003 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
5004 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
5005 }
5006
5007 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
5008
5009 /* FIXME!
5010 * Normalize endianness of structure data,
5011 * by byte-swapping all > 1 byte fields!
5012 */
5013
5014 }
5015
5016 return rc;
5017}
5018
5019/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005020/**
5021 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005022 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005023 * @persist_opcode: see below
5024 *
5025 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
5026 * devices not currently present.
5027 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
5028 *
5029 * NOTE: Don't use not this function during interrupt time.
5030 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005031 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005032 */
5033
5034/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5035int
5036mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
5037{
5038 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
5039 SasIoUnitControlReply_t *sasIoUnitCntrReply;
5040 MPT_FRAME_HDR *mf = NULL;
5041 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305042 int ret = 0;
5043 unsigned long timeleft;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005044
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305045 mutex_lock(&ioc->mptbase_cmds.mutex);
5046
5047 /* init the internal cmd struct */
5048 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
5049 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005050
5051 /* insure garbage is not sent to fw */
5052 switch(persist_opcode) {
5053
5054 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
5055 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
5056 break;
5057
5058 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305059 ret = -1;
5060 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005061 }
5062
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305063 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
5064 __func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005065
5066 /* Get a MF for this command.
5067 */
5068 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305069 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
5070 ret = -1;
5071 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005072 }
5073
5074 mpi_hdr = (MPIHeader_t *) mf;
5075 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
5076 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
5077 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
5078 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
5079 sasIoUnitCntrReq->Operation = persist_opcode;
5080
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005081 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305082 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
5083 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
5084 ret = -ETIME;
5085 printk(KERN_DEBUG "%s: failed\n", __func__);
5086 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
5087 goto out;
5088 if (!timeleft) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09005089 printk(MYIOC_s_WARN_FMT
5090 "Issuing Reset from %s!!, doorbell=0x%08x\n",
5091 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05305092 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305093 mpt_free_msg_frame(ioc, mf);
5094 }
5095 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005096 }
5097
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305098 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
5099 ret = -1;
5100 goto out;
5101 }
5102
5103 sasIoUnitCntrReply =
5104 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5105 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5106 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5107 __func__, sasIoUnitCntrReply->IOCStatus,
5108 sasIoUnitCntrReply->IOCLogInfo);
5109 printk(KERN_DEBUG "%s: failed\n", __func__);
5110 ret = -1;
5111 } else
5112 printk(KERN_DEBUG "%s: success\n", __func__);
5113 out:
5114
5115 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5116 mutex_unlock(&ioc->mptbase_cmds.mutex);
5117 return ret;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005118}
5119
5120/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005121
5122static void
5123mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5124 MpiEventDataRaid_t * pRaidEventData)
5125{
5126 int volume;
5127 int reason;
5128 int disk;
5129 int status;
5130 int flags;
5131 int state;
5132
5133 volume = pRaidEventData->VolumeID;
5134 reason = pRaidEventData->ReasonCode;
5135 disk = pRaidEventData->PhysDiskNum;
5136 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5137 flags = (status >> 0) & 0xff;
5138 state = (status >> 8) & 0xff;
5139
5140 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5141 return;
5142 }
5143
5144 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5145 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5146 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005147 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5148 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005149 } else {
5150 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5151 ioc->name, volume);
5152 }
5153
5154 switch(reason) {
5155 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5156 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5157 ioc->name);
5158 break;
5159
5160 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5161
5162 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5163 ioc->name);
5164 break;
5165
5166 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5167 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5168 ioc->name);
5169 break;
5170
5171 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5172 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5173 ioc->name,
5174 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5175 ? "optimal"
5176 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5177 ? "degraded"
5178 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5179 ? "failed"
5180 : "state unknown",
5181 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5182 ? ", enabled" : "",
5183 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5184 ? ", quiesced" : "",
5185 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5186 ? ", resync in progress" : "" );
5187 break;
5188
5189 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5190 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5191 ioc->name, disk);
5192 break;
5193
5194 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5195 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5196 ioc->name);
5197 break;
5198
5199 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5200 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5201 ioc->name);
5202 break;
5203
5204 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5205 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5206 ioc->name);
5207 break;
5208
5209 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5210 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5211 ioc->name,
5212 state == MPI_PHYSDISK0_STATUS_ONLINE
5213 ? "online"
5214 : state == MPI_PHYSDISK0_STATUS_MISSING
5215 ? "missing"
5216 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5217 ? "not compatible"
5218 : state == MPI_PHYSDISK0_STATUS_FAILED
5219 ? "failed"
5220 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5221 ? "initializing"
5222 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5223 ? "offline requested"
5224 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5225 ? "failed requested"
5226 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5227 ? "offline"
5228 : "state unknown",
5229 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5230 ? ", out of sync" : "",
5231 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5232 ? ", quiesced" : "" );
5233 break;
5234
5235 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5236 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5237 ioc->name, disk);
5238 break;
5239
5240 case MPI_EVENT_RAID_RC_SMART_DATA:
5241 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5242 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5243 break;
5244
5245 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5246 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5247 ioc->name, disk);
5248 break;
5249 }
5250}
5251
5252/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005253/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5255 * @ioc: Pointer to MPT_ADAPTER structure
5256 *
5257 * Returns: 0 for success
5258 * -ENOMEM if no memory available
5259 * -EPERM if not allowed due to ISR context
5260 * -EAGAIN if no msg frames currently available
5261 * -EFAULT for non-successful reply or no reply (timeout)
5262 */
5263static int
5264GetIoUnitPage2(MPT_ADAPTER *ioc)
5265{
5266 ConfigPageHeader_t hdr;
5267 CONFIGPARMS cfg;
5268 IOUnitPage2_t *ppage_alloc;
5269 dma_addr_t page_dma;
5270 int data_sz;
5271 int rc;
5272
5273 /* Get the page header */
5274 hdr.PageVersion = 0;
5275 hdr.PageLength = 0;
5276 hdr.PageNumber = 2;
5277 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005278 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279 cfg.physAddr = -1;
5280 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5281 cfg.dir = 0;
5282 cfg.pageAddr = 0;
5283 cfg.timeout = 0;
5284
5285 if ((rc = mpt_config(ioc, &cfg)) != 0)
5286 return rc;
5287
5288 if (hdr.PageLength == 0)
5289 return 0;
5290
5291 /* Read the config page */
5292 data_sz = hdr.PageLength * 4;
5293 rc = -ENOMEM;
5294 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5295 if (ppage_alloc) {
5296 memset((u8 *)ppage_alloc, 0, data_sz);
5297 cfg.physAddr = page_dma;
5298 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5299
5300 /* If Good, save data */
5301 if ((rc = mpt_config(ioc, &cfg)) == 0)
5302 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5303
5304 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5305 }
5306
5307 return rc;
5308}
5309
5310/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005311/**
5312 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313 * @ioc: Pointer to a Adapter Strucutre
5314 * @portnum: IOC port number
5315 *
5316 * Return: -EFAULT if read of config page header fails
5317 * or if no nvram
5318 * If read of SCSI Port Page 0 fails,
5319 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5320 * Adapter settings: async, narrow
5321 * Return 1
5322 * If read of SCSI Port Page 2 fails,
5323 * Adapter settings valid
5324 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5325 * Return 1
5326 * Else
5327 * Both valid
5328 * Return 0
5329 * CHECK - what type of locking mechanisms should be used????
5330 */
5331static int
5332mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5333{
5334 u8 *pbuf;
5335 dma_addr_t buf_dma;
5336 CONFIGPARMS cfg;
5337 ConfigPageHeader_t header;
5338 int ii;
5339 int data, rc = 0;
5340
5341 /* Allocate memory
5342 */
5343 if (!ioc->spi_data.nvram) {
5344 int sz;
5345 u8 *mem;
5346 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5347 mem = kmalloc(sz, GFP_ATOMIC);
5348 if (mem == NULL)
5349 return -EFAULT;
5350
5351 ioc->spi_data.nvram = (int *) mem;
5352
Prakash, Sathya436ace72007-07-24 15:42:08 +05305353 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005354 ioc->name, ioc->spi_data.nvram, sz));
5355 }
5356
5357 /* Invalidate NVRAM information
5358 */
5359 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5360 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5361 }
5362
5363 /* Read SPP0 header, allocate memory, then read page.
5364 */
5365 header.PageVersion = 0;
5366 header.PageLength = 0;
5367 header.PageNumber = 0;
5368 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005369 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005370 cfg.physAddr = -1;
5371 cfg.pageAddr = portnum;
5372 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5373 cfg.dir = 0;
5374 cfg.timeout = 0; /* use default */
5375 if (mpt_config(ioc, &cfg) != 0)
5376 return -EFAULT;
5377
5378 if (header.PageLength > 0) {
5379 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5380 if (pbuf) {
5381 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5382 cfg.physAddr = buf_dma;
5383 if (mpt_config(ioc, &cfg) != 0) {
5384 ioc->spi_data.maxBusWidth = MPT_NARROW;
5385 ioc->spi_data.maxSyncOffset = 0;
5386 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5387 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5388 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305389 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5390 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005391 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 } else {
5393 /* Save the Port Page 0 data
5394 */
5395 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5396 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5397 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5398
5399 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5400 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005401 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5402 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403 ioc->name, pPP0->Capabilities));
5404 }
5405 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5406 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5407 if (data) {
5408 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5409 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5410 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305411 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5412 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005413 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005414 } else {
5415 ioc->spi_data.maxSyncOffset = 0;
5416 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5417 }
5418
5419 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5420
5421 /* Update the minSyncFactor based on bus type.
5422 */
5423 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5424 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5425
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005426 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305428 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5429 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005430 ioc->name, ioc->spi_data.minSyncFactor));
5431 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432 }
5433 }
5434 if (pbuf) {
5435 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5436 }
5437 }
5438 }
5439
5440 /* SCSI Port Page 2 - Read the header then the page.
5441 */
5442 header.PageVersion = 0;
5443 header.PageLength = 0;
5444 header.PageNumber = 2;
5445 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005446 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447 cfg.physAddr = -1;
5448 cfg.pageAddr = portnum;
5449 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5450 cfg.dir = 0;
5451 if (mpt_config(ioc, &cfg) != 0)
5452 return -EFAULT;
5453
5454 if (header.PageLength > 0) {
5455 /* Allocate memory and read SCSI Port Page 2
5456 */
5457 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5458 if (pbuf) {
5459 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5460 cfg.physAddr = buf_dma;
5461 if (mpt_config(ioc, &cfg) != 0) {
5462 /* Nvram data is left with INVALID mark
5463 */
5464 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005465 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5466
5467 /* This is an ATTO adapter, read Page2 accordingly
5468 */
5469 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5470 ATTODeviceInfo_t *pdevice = NULL;
5471 u16 ATTOFlags;
5472
5473 /* Save the Port Page 2 data
5474 * (reformat into a 32bit quantity)
5475 */
5476 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5477 pdevice = &pPP2->DeviceSettings[ii];
5478 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5479 data = 0;
5480
5481 /* Translate ATTO device flags to LSI format
5482 */
5483 if (ATTOFlags & ATTOFLAG_DISC)
5484 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5485 if (ATTOFlags & ATTOFLAG_ID_ENB)
5486 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5487 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5488 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5489 if (ATTOFlags & ATTOFLAG_TAGGED)
5490 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5491 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5492 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5493
5494 data = (data << 16) | (pdevice->Period << 8) | 10;
5495 ioc->spi_data.nvram[ii] = data;
5496 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 } else {
5498 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5499 MpiDeviceInfo_t *pdevice = NULL;
5500
Moore, Ericd8e925d2006-01-16 18:53:06 -07005501 /*
5502 * Save "Set to Avoid SCSI Bus Resets" flag
5503 */
5504 ioc->spi_data.bus_reset =
5505 (le32_to_cpu(pPP2->PortFlags) &
5506 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5507 0 : 1 ;
5508
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 /* Save the Port Page 2 data
5510 * (reformat into a 32bit quantity)
5511 */
5512 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5513 ioc->spi_data.PortFlags = data;
5514 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5515 pdevice = &pPP2->DeviceSettings[ii];
5516 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5517 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5518 ioc->spi_data.nvram[ii] = data;
5519 }
5520 }
5521
5522 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5523 }
5524 }
5525
5526 /* Update Adapter limits with those from NVRAM
5527 * Comment: Don't need to do this. Target performance
5528 * parameters will never exceed the adapters limits.
5529 */
5530
5531 return rc;
5532}
5533
5534/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005535/**
5536 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537 * @ioc: Pointer to a Adapter Strucutre
5538 * @portnum: IOC port number
5539 *
5540 * Return: -EFAULT if read of config page header fails
5541 * or 0 if success.
5542 */
5543static int
5544mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5545{
5546 CONFIGPARMS cfg;
5547 ConfigPageHeader_t header;
5548
5549 /* Read the SCSI Device Page 1 header
5550 */
5551 header.PageVersion = 0;
5552 header.PageLength = 0;
5553 header.PageNumber = 1;
5554 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005555 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556 cfg.physAddr = -1;
5557 cfg.pageAddr = portnum;
5558 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5559 cfg.dir = 0;
5560 cfg.timeout = 0;
5561 if (mpt_config(ioc, &cfg) != 0)
5562 return -EFAULT;
5563
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005564 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5565 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566
5567 header.PageVersion = 0;
5568 header.PageLength = 0;
5569 header.PageNumber = 0;
5570 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5571 if (mpt_config(ioc, &cfg) != 0)
5572 return -EFAULT;
5573
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005574 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5575 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576
Prakash, Sathya436ace72007-07-24 15:42:08 +05305577 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5579
Prakash, Sathya436ace72007-07-24 15:42:08 +05305580 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5582 return 0;
5583}
5584
Eric Mooreb506ade2007-01-29 09:45:37 -07005585/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005586 * mpt_inactive_raid_list_free - This clears this link list.
5587 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005588 **/
5589static void
5590mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5591{
5592 struct inactive_raid_component_info *component_info, *pNext;
5593
5594 if (list_empty(&ioc->raid_data.inactive_list))
5595 return;
5596
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005597 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005598 list_for_each_entry_safe(component_info, pNext,
5599 &ioc->raid_data.inactive_list, list) {
5600 list_del(&component_info->list);
5601 kfree(component_info);
5602 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005603 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005604}
5605
5606/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005607 * 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 -07005608 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005609 * @ioc : pointer to per adapter structure
5610 * @channel : volume channel
5611 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005612 **/
5613static void
5614mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5615{
5616 CONFIGPARMS cfg;
5617 ConfigPageHeader_t hdr;
5618 dma_addr_t dma_handle;
5619 pRaidVolumePage0_t buffer = NULL;
5620 int i;
5621 RaidPhysDiskPage0_t phys_disk;
5622 struct inactive_raid_component_info *component_info;
5623 int handle_inactive_volumes;
5624
5625 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5626 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5627 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5628 cfg.pageAddr = (channel << 8) + id;
5629 cfg.cfghdr.hdr = &hdr;
5630 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5631
5632 if (mpt_config(ioc, &cfg) != 0)
5633 goto out;
5634
5635 if (!hdr.PageLength)
5636 goto out;
5637
5638 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5639 &dma_handle);
5640
5641 if (!buffer)
5642 goto out;
5643
5644 cfg.physAddr = dma_handle;
5645 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5646
5647 if (mpt_config(ioc, &cfg) != 0)
5648 goto out;
5649
5650 if (!buffer->NumPhysDisks)
5651 goto out;
5652
5653 handle_inactive_volumes =
5654 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5655 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5656 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5657 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5658
5659 if (!handle_inactive_volumes)
5660 goto out;
5661
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005662 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005663 for (i = 0; i < buffer->NumPhysDisks; i++) {
5664 if(mpt_raid_phys_disk_pg0(ioc,
5665 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5666 continue;
5667
5668 if ((component_info = kmalloc(sizeof (*component_info),
5669 GFP_KERNEL)) == NULL)
5670 continue;
5671
5672 component_info->volumeID = id;
5673 component_info->volumeBus = channel;
5674 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5675 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5676 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5677 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5678
5679 list_add_tail(&component_info->list,
5680 &ioc->raid_data.inactive_list);
5681 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005682 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005683
5684 out:
5685 if (buffer)
5686 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5687 dma_handle);
5688}
5689
5690/**
5691 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5692 * @ioc: Pointer to a Adapter Structure
5693 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5694 * @phys_disk: requested payload data returned
5695 *
5696 * Return:
5697 * 0 on success
5698 * -EFAULT if read of config page header fails or data pointer not NULL
5699 * -ENOMEM if pci_alloc failed
5700 **/
5701int
Kashyap, Desai2f187862009-05-29 16:52:37 +05305702mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
5703 RaidPhysDiskPage0_t *phys_disk)
Eric Mooreb506ade2007-01-29 09:45:37 -07005704{
Kashyap, Desai2f187862009-05-29 16:52:37 +05305705 CONFIGPARMS cfg;
5706 ConfigPageHeader_t hdr;
Eric Mooreb506ade2007-01-29 09:45:37 -07005707 dma_addr_t dma_handle;
5708 pRaidPhysDiskPage0_t buffer = NULL;
5709 int rc;
5710
5711 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5712 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
Kashyap, Desai2f187862009-05-29 16:52:37 +05305713 memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
Eric Mooreb506ade2007-01-29 09:45:37 -07005714
Kashyap, Desai2f187862009-05-29 16:52:37 +05305715 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
Eric Mooreb506ade2007-01-29 09:45:37 -07005716 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5717 cfg.cfghdr.hdr = &hdr;
5718 cfg.physAddr = -1;
5719 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5720
5721 if (mpt_config(ioc, &cfg) != 0) {
5722 rc = -EFAULT;
5723 goto out;
5724 }
5725
5726 if (!hdr.PageLength) {
5727 rc = -EFAULT;
5728 goto out;
5729 }
5730
5731 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5732 &dma_handle);
5733
5734 if (!buffer) {
5735 rc = -ENOMEM;
5736 goto out;
5737 }
5738
5739 cfg.physAddr = dma_handle;
5740 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5741 cfg.pageAddr = phys_disk_num;
5742
5743 if (mpt_config(ioc, &cfg) != 0) {
5744 rc = -EFAULT;
5745 goto out;
5746 }
5747
5748 rc = 0;
5749 memcpy(phys_disk, buffer, sizeof(*buffer));
5750 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5751
5752 out:
5753
5754 if (buffer)
5755 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5756 dma_handle);
5757
5758 return rc;
5759}
5760
Linus Torvalds1da177e2005-04-16 15:20:36 -07005761/**
Kashyap, Desaia7938b02009-05-29 16:53:56 +05305762 * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
5763 * @ioc: Pointer to a Adapter Structure
5764 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5765 *
5766 * Return:
5767 * returns number paths
5768 **/
5769int
5770mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
5771{
5772 CONFIGPARMS cfg;
5773 ConfigPageHeader_t hdr;
5774 dma_addr_t dma_handle;
5775 pRaidPhysDiskPage1_t buffer = NULL;
5776 int rc;
5777
5778 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5779 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5780
5781 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5782 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5783 hdr.PageNumber = 1;
5784 cfg.cfghdr.hdr = &hdr;
5785 cfg.physAddr = -1;
5786 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5787
5788 if (mpt_config(ioc, &cfg) != 0) {
5789 rc = 0;
5790 goto out;
5791 }
5792
5793 if (!hdr.PageLength) {
5794 rc = 0;
5795 goto out;
5796 }
5797
5798 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5799 &dma_handle);
5800
5801 if (!buffer) {
5802 rc = 0;
5803 goto out;
5804 }
5805
5806 cfg.physAddr = dma_handle;
5807 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5808 cfg.pageAddr = phys_disk_num;
5809
5810 if (mpt_config(ioc, &cfg) != 0) {
5811 rc = 0;
5812 goto out;
5813 }
5814
5815 rc = buffer->NumPhysDiskPaths;
5816 out:
5817
5818 if (buffer)
5819 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5820 dma_handle);
5821
5822 return rc;
5823}
5824EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
5825
5826/**
5827 * mpt_raid_phys_disk_pg1 - returns phys disk page 1
5828 * @ioc: Pointer to a Adapter Structure
5829 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5830 * @phys_disk: requested payload data returned
5831 *
5832 * Return:
5833 * 0 on success
5834 * -EFAULT if read of config page header fails or data pointer not NULL
5835 * -ENOMEM if pci_alloc failed
5836 **/
5837int
5838mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
5839 RaidPhysDiskPage1_t *phys_disk)
5840{
5841 CONFIGPARMS cfg;
5842 ConfigPageHeader_t hdr;
5843 dma_addr_t dma_handle;
5844 pRaidPhysDiskPage1_t buffer = NULL;
5845 int rc;
5846 int i;
5847 __le64 sas_address;
5848
5849 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5850 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5851 rc = 0;
5852
5853 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5854 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5855 hdr.PageNumber = 1;
5856 cfg.cfghdr.hdr = &hdr;
5857 cfg.physAddr = -1;
5858 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5859
5860 if (mpt_config(ioc, &cfg) != 0) {
5861 rc = -EFAULT;
5862 goto out;
5863 }
5864
5865 if (!hdr.PageLength) {
5866 rc = -EFAULT;
5867 goto out;
5868 }
5869
5870 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5871 &dma_handle);
5872
5873 if (!buffer) {
5874 rc = -ENOMEM;
5875 goto out;
5876 }
5877
5878 cfg.physAddr = dma_handle;
5879 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5880 cfg.pageAddr = phys_disk_num;
5881
5882 if (mpt_config(ioc, &cfg) != 0) {
5883 rc = -EFAULT;
5884 goto out;
5885 }
5886
5887 phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
5888 phys_disk->PhysDiskNum = phys_disk_num;
5889 for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
5890 phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
5891 phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
5892 phys_disk->Path[i].OwnerIdentifier =
5893 buffer->Path[i].OwnerIdentifier;
5894 phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
5895 memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
5896 sas_address = le64_to_cpu(sas_address);
5897 memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
5898 memcpy(&sas_address,
5899 &buffer->Path[i].OwnerWWID, sizeof(__le64));
5900 sas_address = le64_to_cpu(sas_address);
5901 memcpy(&phys_disk->Path[i].OwnerWWID,
5902 &sas_address, sizeof(__le64));
5903 }
5904
5905 out:
5906
5907 if (buffer)
5908 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5909 dma_handle);
5910
5911 return rc;
5912}
5913EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
5914
5915
5916/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005917 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5918 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919 *
5920 * Return:
5921 * 0 on success
5922 * -EFAULT if read of config page header fails or data pointer not NULL
5923 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005924 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005925int
5926mpt_findImVolumes(MPT_ADAPTER *ioc)
5927{
5928 IOCPage2_t *pIoc2;
5929 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005930 dma_addr_t ioc2_dma;
5931 CONFIGPARMS cfg;
5932 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005933 int rc = 0;
5934 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005935 int i;
5936
5937 if (!ioc->ir_firmware)
5938 return 0;
5939
5940 /* Free the old page
5941 */
5942 kfree(ioc->raid_data.pIocPg2);
5943 ioc->raid_data.pIocPg2 = NULL;
5944 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005945
5946 /* Read IOCP2 header then the page.
5947 */
5948 header.PageVersion = 0;
5949 header.PageLength = 0;
5950 header.PageNumber = 2;
5951 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005952 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953 cfg.physAddr = -1;
5954 cfg.pageAddr = 0;
5955 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5956 cfg.dir = 0;
5957 cfg.timeout = 0;
5958 if (mpt_config(ioc, &cfg) != 0)
5959 return -EFAULT;
5960
5961 if (header.PageLength == 0)
5962 return -EFAULT;
5963
5964 iocpage2sz = header.PageLength * 4;
5965 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5966 if (!pIoc2)
5967 return -ENOMEM;
5968
5969 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5970 cfg.physAddr = ioc2_dma;
5971 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005972 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005973
Eric Mooreb506ade2007-01-29 09:45:37 -07005974 mem = kmalloc(iocpage2sz, GFP_KERNEL);
Julia Lawall1c1acab2010-08-11 12:11:24 +02005975 if (!mem) {
5976 rc = -ENOMEM;
Eric Mooreb506ade2007-01-29 09:45:37 -07005977 goto out;
Julia Lawall1c1acab2010-08-11 12:11:24 +02005978 }
Eric Mooreb506ade2007-01-29 09:45:37 -07005979
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005981 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982
Eric Mooreb506ade2007-01-29 09:45:37 -07005983 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005984
Eric Mooreb506ade2007-01-29 09:45:37 -07005985 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5986 mpt_inactive_raid_volumes(ioc,
5987 pIoc2->RaidVolume[i].VolumeBus,
5988 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005989
Eric Mooreb506ade2007-01-29 09:45:37 -07005990 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005991 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5992
5993 return rc;
5994}
5995
Moore, Ericc972c702006-03-14 09:14:06 -07005996static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005997mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5998{
5999 IOCPage3_t *pIoc3;
6000 u8 *mem;
6001 CONFIGPARMS cfg;
6002 ConfigPageHeader_t header;
6003 dma_addr_t ioc3_dma;
6004 int iocpage3sz = 0;
6005
6006 /* Free the old page
6007 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006008 kfree(ioc->raid_data.pIocPg3);
6009 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006010
6011 /* There is at least one physical disk.
6012 * Read and save IOC Page 3
6013 */
6014 header.PageVersion = 0;
6015 header.PageLength = 0;
6016 header.PageNumber = 3;
6017 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006018 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006019 cfg.physAddr = -1;
6020 cfg.pageAddr = 0;
6021 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6022 cfg.dir = 0;
6023 cfg.timeout = 0;
6024 if (mpt_config(ioc, &cfg) != 0)
6025 return 0;
6026
6027 if (header.PageLength == 0)
6028 return 0;
6029
6030 /* Read Header good, alloc memory
6031 */
6032 iocpage3sz = header.PageLength * 4;
6033 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
6034 if (!pIoc3)
6035 return 0;
6036
6037 /* Read the Page and save the data
6038 * into malloc'd memory.
6039 */
6040 cfg.physAddr = ioc3_dma;
6041 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6042 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07006043 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006044 if (mem) {
6045 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006046 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006047 }
6048 }
6049
6050 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
6051
6052 return 0;
6053}
6054
6055static void
6056mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
6057{
6058 IOCPage4_t *pIoc4;
6059 CONFIGPARMS cfg;
6060 ConfigPageHeader_t header;
6061 dma_addr_t ioc4_dma;
6062 int iocpage4sz;
6063
6064 /* Read and save IOC Page 4
6065 */
6066 header.PageVersion = 0;
6067 header.PageLength = 0;
6068 header.PageNumber = 4;
6069 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006070 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071 cfg.physAddr = -1;
6072 cfg.pageAddr = 0;
6073 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6074 cfg.dir = 0;
6075 cfg.timeout = 0;
6076 if (mpt_config(ioc, &cfg) != 0)
6077 return;
6078
6079 if (header.PageLength == 0)
6080 return;
6081
6082 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
6083 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
6084 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
6085 if (!pIoc4)
6086 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06006087 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006088 } else {
6089 ioc4_dma = ioc->spi_data.IocPg4_dma;
6090 iocpage4sz = ioc->spi_data.IocPg4Sz;
6091 }
6092
6093 /* Read the Page into dma memory.
6094 */
6095 cfg.physAddr = ioc4_dma;
6096 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6097 if (mpt_config(ioc, &cfg) == 0) {
6098 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
6099 ioc->spi_data.IocPg4_dma = ioc4_dma;
6100 ioc->spi_data.IocPg4Sz = iocpage4sz;
6101 } else {
6102 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
6103 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06006104 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006105 }
6106}
6107
6108static void
6109mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
6110{
6111 IOCPage1_t *pIoc1;
6112 CONFIGPARMS cfg;
6113 ConfigPageHeader_t header;
6114 dma_addr_t ioc1_dma;
6115 int iocpage1sz = 0;
6116 u32 tmp;
6117
6118 /* Check the Coalescing Timeout in IOC Page 1
6119 */
6120 header.PageVersion = 0;
6121 header.PageLength = 0;
6122 header.PageNumber = 1;
6123 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006124 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006125 cfg.physAddr = -1;
6126 cfg.pageAddr = 0;
6127 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6128 cfg.dir = 0;
6129 cfg.timeout = 0;
6130 if (mpt_config(ioc, &cfg) != 0)
6131 return;
6132
6133 if (header.PageLength == 0)
6134 return;
6135
6136 /* Read Header good, alloc memory
6137 */
6138 iocpage1sz = header.PageLength * 4;
6139 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
6140 if (!pIoc1)
6141 return;
6142
6143 /* Read the Page and check coalescing timeout
6144 */
6145 cfg.physAddr = ioc1_dma;
6146 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6147 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306148
Linus Torvalds1da177e2005-04-16 15:20:36 -07006149 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
6150 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
6151 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
6152
Prakash, Sathya436ace72007-07-24 15:42:08 +05306153 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006154 ioc->name, tmp));
6155
6156 if (tmp > MPT_COALESCING_TIMEOUT) {
6157 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
6158
6159 /* Write NVRAM and current
6160 */
6161 cfg.dir = 1;
6162 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
6163 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306164 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006165 ioc->name, MPT_COALESCING_TIMEOUT));
6166
6167 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
6168 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306169 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6170 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006171 ioc->name, MPT_COALESCING_TIMEOUT));
6172 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306173 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6174 "Reset NVRAM Coalescing Timeout Failed\n",
6175 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006176 }
6177
6178 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306179 dprintk(ioc, printk(MYIOC_s_WARN_FMT
6180 "Reset of Current Coalescing Timeout Failed!\n",
6181 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006182 }
6183 }
6184
6185 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306186 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006187 }
6188 }
6189
6190 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
6191
6192 return;
6193}
6194
Prakash, Sathyaedb90682007-07-17 14:39:14 +05306195static void
6196mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
6197{
6198 CONFIGPARMS cfg;
6199 ConfigPageHeader_t hdr;
6200 dma_addr_t buf_dma;
6201 ManufacturingPage0_t *pbuf = NULL;
6202
6203 memset(&cfg, 0 , sizeof(CONFIGPARMS));
6204 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
6205
6206 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
6207 cfg.cfghdr.hdr = &hdr;
6208 cfg.physAddr = -1;
6209 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6210 cfg.timeout = 10;
6211
6212 if (mpt_config(ioc, &cfg) != 0)
6213 goto out;
6214
6215 if (!cfg.cfghdr.hdr->PageLength)
6216 goto out;
6217
6218 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6219 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
6220 if (!pbuf)
6221 goto out;
6222
6223 cfg.physAddr = buf_dma;
6224
6225 if (mpt_config(ioc, &cfg) != 0)
6226 goto out;
6227
6228 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
6229 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
6230 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
6231
6232 out:
6233
6234 if (pbuf)
6235 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
6236}
6237
Linus Torvalds1da177e2005-04-16 15:20:36 -07006238/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006239/**
6240 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241 * @ioc: Pointer to MPT_ADAPTER structure
6242 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05306243 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07006244 */
6245static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05306246SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006247{
Kashyap, Desaifd761752009-05-29 16:39:06 +05306248 EventNotification_t evn;
6249 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006250
Kashyap, Desaifd761752009-05-29 16:39:06 +05306251 memset(&evn, 0, sizeof(EventNotification_t));
6252 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006253
Kashyap, Desaifd761752009-05-29 16:39:06 +05306254 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
6255 evn.Switch = EvSwitch;
6256 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006257
Kashyap, Desaifd761752009-05-29 16:39:06 +05306258 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6259 "Sending EventNotification (%d) request %p\n",
6260 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006261
Kashyap, Desaifd761752009-05-29 16:39:06 +05306262 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6263 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6264 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006265}
6266
6267/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6268/**
6269 * SendEventAck - Send EventAck request to MPT adapter.
6270 * @ioc: Pointer to MPT_ADAPTER structure
6271 * @evnp: Pointer to original EventNotification request
6272 */
6273static int
6274SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6275{
6276 EventAck_t *pAck;
6277
6278 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306279 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306280 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006281 return -1;
6282 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006283
Prakash, Sathya436ace72007-07-24 15:42:08 +05306284 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006285
6286 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6287 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006288 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006289 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006290 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006291 pAck->Event = evnp->Event;
6292 pAck->EventContext = evnp->EventContext;
6293
6294 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6295
6296 return 0;
6297}
6298
6299/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6300/**
6301 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006302 * @ioc: Pointer to an adapter structure
6303 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006304 * action, page address, direction, physical address
6305 * and pointer to a configuration page header
6306 * Page header is updated.
6307 *
6308 * Returns 0 for success
6309 * -EPERM if not allowed due to ISR context
6310 * -EAGAIN if no msg frames currently available
6311 * -EFAULT for non-successful reply or no reply (timeout)
6312 */
6313int
6314mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6315{
6316 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306317 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006318 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006319 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306320 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006321 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306322 long timeout;
6323 int ret;
6324 u8 page_type = 0, extend_page;
6325 unsigned long timeleft;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306326 unsigned long flags;
6327 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306328 u8 issue_hard_reset = 0;
6329 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006330
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006331 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006332 * to be in ISR context, because that is fatal!
6333 */
6334 in_isr = in_interrupt();
6335 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306336 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006337 ioc->name));
6338 return -EPERM;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306339 }
6340
6341 /* don't send a config page during diag reset */
6342 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6343 if (ioc->ioc_reset_in_progress) {
6344 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6345 "%s: busy with host reset\n", ioc->name, __func__));
6346 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6347 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006348 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306349 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006350
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306351 /* don't send if no chance of success */
6352 if (!ioc->active ||
6353 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6354 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6355 "%s: ioc not operational, %d, %xh\n",
6356 ioc->name, __func__, ioc->active,
6357 mpt_GetIocState(ioc, 0)));
6358 return -EFAULT;
6359 }
6360
6361 retry_config:
6362 mutex_lock(&ioc->mptbase_cmds.mutex);
6363 /* init the internal cmd struct */
6364 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6365 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6366
Linus Torvalds1da177e2005-04-16 15:20:36 -07006367 /* Get and Populate a free Frame
6368 */
6369 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306370 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6371 "mpt_config: no msg frames!\n", ioc->name));
6372 ret = -EAGAIN;
6373 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006374 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306375
Linus Torvalds1da177e2005-04-16 15:20:36 -07006376 pReq = (Config_t *)mf;
6377 pReq->Action = pCfg->action;
6378 pReq->Reserved = 0;
6379 pReq->ChainOffset = 0;
6380 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006381
6382 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006383 pReq->ExtPageLength = 0;
6384 pReq->ExtPageType = 0;
6385 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006386
Linus Torvalds1da177e2005-04-16 15:20:36 -07006387 for (ii=0; ii < 8; ii++)
6388 pReq->Reserved2[ii] = 0;
6389
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006390 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6391 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6392 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6393 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6394
6395 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6396 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6397 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6398 pReq->ExtPageType = pExtHdr->ExtPageType;
6399 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6400
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306401 /* Page Length must be treated as a reserved field for the
6402 * extended header.
6403 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006404 pReq->Header.PageLength = 0;
6405 }
6406
Linus Torvalds1da177e2005-04-16 15:20:36 -07006407 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6408
6409 /* Add a SGE to the config request.
6410 */
6411 if (pCfg->dir)
6412 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6413 else
6414 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6415
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306416 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6417 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006418 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306419 page_type = pReq->ExtPageType;
6420 extend_page = 1;
6421 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006422 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306423 page_type = pReq->Header.PageType;
6424 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006425 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006426
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306427 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6428 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6429 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6430
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306431 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306432 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006433 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306434 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6435 timeout);
6436 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6437 ret = -ETIME;
6438 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6439 "Failed Sending Config request type 0x%x, page 0x%x,"
6440 " action %d, status %xh, time left %ld\n\n",
6441 ioc->name, page_type, pReq->Header.PageNumber,
6442 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6443 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6444 goto out;
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05306445 if (!timeleft) {
6446 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6447 if (ioc->ioc_reset_in_progress) {
6448 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
6449 flags);
6450 printk(MYIOC_s_INFO_FMT "%s: host reset in"
6451 " progress mpt_config timed out.!!\n",
6452 __func__, ioc->name);
Dan Carpenter83ff74e2011-08-27 12:59:30 +03006453 mutex_unlock(&ioc->mptbase_cmds.mutex);
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05306454 return -EFAULT;
6455 }
6456 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306457 issue_hard_reset = 1;
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05306458 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306459 goto out;
6460 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006461
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306462 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6463 ret = -1;
6464 goto out;
6465 }
6466 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6467 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6468 if (ret == MPI_IOCSTATUS_SUCCESS) {
6469 if (extend_page) {
6470 pCfg->cfghdr.ehdr->ExtPageLength =
6471 le16_to_cpu(pReply->ExtPageLength);
6472 pCfg->cfghdr.ehdr->ExtPageType =
6473 pReply->ExtPageType;
6474 }
6475 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6476 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6477 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6478 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006479
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306480 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006481
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306482 if (retry_count)
6483 printk(MYIOC_s_INFO_FMT "Retry completed "
6484 "ret=0x%x timeleft=%ld\n",
6485 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006486
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306487 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6488 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006489
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306490out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006491
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306492 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6493 mutex_unlock(&ioc->mptbase_cmds.mutex);
6494 if (issue_hard_reset) {
6495 issue_hard_reset = 0;
Kei Tokunaga97009a22010-06-22 19:01:51 +09006496 printk(MYIOC_s_WARN_FMT
6497 "Issuing Reset from %s!!, doorbell=0x%08x\n",
6498 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaib3b97312010-03-18 19:14:51 +05306499 if (retry_count == 0) {
6500 if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0)
6501 retry_count++;
6502 } else
6503 mpt_HardResetHandler(ioc, CAN_SLEEP);
6504
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306505 mpt_free_msg_frame(ioc, mf);
6506 /* attempt one retry for a timed out command */
Kashyap, Desaib3b97312010-03-18 19:14:51 +05306507 if (retry_count < 2) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306508 printk(MYIOC_s_INFO_FMT
6509 "Attempting Retry Config request"
6510 " type 0x%x, page 0x%x,"
6511 " action %d\n", ioc->name, page_type,
6512 pCfg->cfghdr.hdr->PageNumber, pCfg->action);
6513 retry_count++;
6514 goto retry_config;
6515 }
6516 }
6517 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006518
Linus Torvalds1da177e2005-04-16 15:20:36 -07006519}
6520
6521/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006522/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006523 * mpt_ioc_reset - Base cleanup for hard reset
6524 * @ioc: Pointer to the adapter structure
6525 * @reset_phase: Indicates pre- or post-reset functionality
6526 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006527 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006528 */
6529static int
6530mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6531{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306532 switch (reset_phase) {
6533 case MPT_IOC_SETUP_RESET:
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306534 ioc->taskmgmt_quiesce_io = 1;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306535 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6536 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
6537 break;
6538 case MPT_IOC_PRE_RESET:
6539 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6540 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
6541 break;
6542 case MPT_IOC_POST_RESET:
6543 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6544 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
6545/* wake up mptbase_cmds */
6546 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6547 ioc->mptbase_cmds.status |=
6548 MPT_MGMT_STATUS_DID_IOCRESET;
6549 complete(&ioc->mptbase_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006550 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306551/* wake up taskmgmt_cmds */
6552 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
6553 ioc->taskmgmt_cmds.status |=
6554 MPT_MGMT_STATUS_DID_IOCRESET;
6555 complete(&ioc->taskmgmt_cmds.done);
6556 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306557 break;
6558 default:
6559 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006560 }
6561
6562 return 1; /* currently means nothing really */
6563}
6564
6565
6566#ifdef CONFIG_PROC_FS /* { */
6567/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6568/*
6569 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6570 */
6571/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006572/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006573 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6574 *
6575 * Returns 0 for success, non-zero for failure.
6576 */
6577static int
6578procmpt_create(void)
6579{
Linus Torvalds1da177e2005-04-16 15:20:36 -07006580 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6581 if (mpt_proc_root_dir == NULL)
6582 return -ENOTDIR;
6583
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006584 proc_create("summary", S_IRUGO, mpt_proc_root_dir, &mpt_summary_proc_fops);
6585 proc_create("version", S_IRUGO, mpt_proc_root_dir, &mpt_version_proc_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006586 return 0;
6587}
6588
6589/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006590/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006591 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6592 *
6593 * Returns 0 for success, non-zero for failure.
6594 */
6595static void
6596procmpt_destroy(void)
6597{
6598 remove_proc_entry("version", mpt_proc_root_dir);
6599 remove_proc_entry("summary", mpt_proc_root_dir);
6600 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6601}
6602
6603/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlap1f5cfe22010-08-14 13:05:50 -07006604/*
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006605 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006606 */
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006607static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan);
6608
6609static int mpt_summary_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006610{
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006611 MPT_ADAPTER *ioc = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006612
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006613 if (ioc) {
6614 seq_mpt_print_ioc_summary(ioc, m, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006615 } else {
6616 list_for_each_entry(ioc, &ioc_list, list) {
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006617 seq_mpt_print_ioc_summary(ioc, m, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006618 }
6619 }
6620
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006621 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006622}
6623
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006624static int mpt_summary_proc_open(struct inode *inode, struct file *file)
6625{
Al Virod9dda782013-03-31 18:16:14 -04006626 return single_open(file, mpt_summary_proc_show, PDE_DATA(inode));
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006627}
6628
6629static const struct file_operations mpt_summary_proc_fops = {
6630 .owner = THIS_MODULE,
6631 .open = mpt_summary_proc_open,
6632 .read = seq_read,
6633 .llseek = seq_lseek,
6634 .release = single_release,
6635};
6636
6637static int mpt_version_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006638{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306639 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006640 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006641 char *drvname;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006642
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006643 seq_printf(m, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6644 seq_printf(m, " Fusion MPT base driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006645
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006646 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006647 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006648 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306649 if (MptCallbacks[cb_idx]) {
6650 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006651 case MPTSPI_DRIVER:
6652 if (!scsi++) drvname = "SPI host";
6653 break;
6654 case MPTFC_DRIVER:
6655 if (!fc++) drvname = "FC host";
6656 break;
6657 case MPTSAS_DRIVER:
6658 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006659 break;
6660 case MPTLAN_DRIVER:
6661 if (!lan++) drvname = "LAN";
6662 break;
6663 case MPTSTM_DRIVER:
6664 if (!targ++) drvname = "SCSI target";
6665 break;
6666 case MPTCTL_DRIVER:
6667 if (!ctl++) drvname = "ioctl";
6668 break;
6669 }
6670
6671 if (drvname)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006672 seq_printf(m, " Fusion MPT %s driver\n", drvname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006673 }
6674 }
6675
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006676 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006677}
6678
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006679static int mpt_version_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006680{
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006681 return single_open(file, mpt_version_proc_show, NULL);
6682}
6683
6684static const struct file_operations mpt_version_proc_fops = {
6685 .owner = THIS_MODULE,
6686 .open = mpt_version_proc_open,
6687 .read = seq_read,
6688 .llseek = seq_lseek,
6689 .release = single_release,
6690};
6691
6692static int mpt_iocinfo_proc_show(struct seq_file *m, void *v)
6693{
6694 MPT_ADAPTER *ioc = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006695 char expVer[32];
6696 int sz;
6697 int p;
6698
6699 mpt_get_fw_exp_ver(expVer, ioc);
6700
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006701 seq_printf(m, "%s:", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006702 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006703 seq_printf(m, " (f/w download boot flag set)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006704// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006705// seq_printf(m, " CONFIG_CHECKSUM_FAIL!");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006706
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006707 seq_printf(m, "\n ProductID = 0x%04x (%s)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006708 ioc->facts.ProductID,
6709 ioc->prod_name);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006710 seq_printf(m, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006711 if (ioc->facts.FWImageSize)
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006712 seq_printf(m, " (fw_size=%d)", ioc->facts.FWImageSize);
6713 seq_printf(m, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6714 seq_printf(m, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6715 seq_printf(m, " EventState = 0x%02x\n", ioc->facts.EventState);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006716
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006717 seq_printf(m, " CurrentHostMfaHighAddr = 0x%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006718 ioc->facts.CurrentHostMfaHighAddr);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006719 seq_printf(m, " CurrentSenseBufferHighAddr = 0x%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006720 ioc->facts.CurrentSenseBufferHighAddr);
6721
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006722 seq_printf(m, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6723 seq_printf(m, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006724
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006725 seq_printf(m, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006726 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6727 /*
6728 * Rounding UP to nearest 4-kB boundary here...
6729 */
6730 sz = (ioc->req_sz * ioc->req_depth) + 128;
6731 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006732 seq_printf(m, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006733 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006734 seq_printf(m, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006735 4*ioc->facts.RequestFrameSize,
6736 ioc->facts.GlobalCredits);
6737
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006738 seq_printf(m, " Frames @ 0x%p (Dma @ 0x%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006739 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6740 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006741 seq_printf(m, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006742 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006743 seq_printf(m, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006744 ioc->facts.CurReplyFrameSize,
6745 ioc->facts.ReplyQueueDepth);
6746
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006747 seq_printf(m, " MaxDevices = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006748 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006749 seq_printf(m, " MaxBuses = %d\n", ioc->facts.MaxBuses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006750
6751 /* per-port info */
6752 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006753 seq_printf(m, " PortNumber = %d (of %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006754 p+1,
6755 ioc->facts.NumberOfPorts);
6756 if (ioc->bus_type == FC) {
6757 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6758 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006759 seq_printf(m, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006760 a[5], a[4], a[3], a[2], a[1], a[0]);
6761 }
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006762 seq_printf(m, " WWN = %08X%08X:%08X%08X\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006763 ioc->fc_port_page0[p].WWNN.High,
6764 ioc->fc_port_page0[p].WWNN.Low,
6765 ioc->fc_port_page0[p].WWPN.High,
6766 ioc->fc_port_page0[p].WWPN.Low);
6767 }
6768 }
6769
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006770 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006771}
6772
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006773static int mpt_iocinfo_proc_open(struct inode *inode, struct file *file)
6774{
Al Virod9dda782013-03-31 18:16:14 -04006775 return single_open(file, mpt_iocinfo_proc_show, PDE_DATA(inode));
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006776}
6777
6778static const struct file_operations mpt_iocinfo_proc_fops = {
6779 .owner = THIS_MODULE,
6780 .open = mpt_iocinfo_proc_open,
6781 .read = seq_read,
6782 .llseek = seq_lseek,
6783 .release = single_release,
6784};
Linus Torvalds1da177e2005-04-16 15:20:36 -07006785#endif /* CONFIG_PROC_FS } */
6786
6787/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6788static void
6789mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6790{
6791 buf[0] ='\0';
6792 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6793 sprintf(buf, " (Exp %02d%02d)",
6794 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6795 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6796
6797 /* insider hack! */
6798 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6799 strcat(buf, " [MDBG]");
6800 }
6801}
6802
6803/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6804/**
6805 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6806 * @ioc: Pointer to MPT_ADAPTER structure
6807 * @buffer: Pointer to buffer where IOC summary info should be written
6808 * @size: Pointer to number of bytes we wrote (set by this routine)
6809 * @len: Offset at which to start writing in buffer
6810 * @showlan: Display LAN stuff?
6811 *
6812 * This routine writes (english readable) ASCII text, which represents
6813 * a summary of IOC information, to a buffer.
6814 */
6815void
6816mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6817{
6818 char expVer[32];
6819 int y;
6820
6821 mpt_get_fw_exp_ver(expVer, ioc);
6822
6823 /*
6824 * Shorter summary of attached ioc's...
6825 */
6826 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6827 ioc->name,
6828 ioc->prod_name,
6829 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6830 ioc->facts.FWVersion.Word,
6831 expVer,
6832 ioc->facts.NumberOfPorts,
6833 ioc->req_depth);
6834
6835 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6836 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6837 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6838 a[5], a[4], a[3], a[2], a[1], a[0]);
6839 }
6840
Linus Torvalds1da177e2005-04-16 15:20:36 -07006841 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006842
6843 if (!ioc->active)
6844 y += sprintf(buffer+len+y, " (disabled)");
6845
6846 y += sprintf(buffer+len+y, "\n");
6847
6848 *size = y;
6849}
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006850
Arnd Bergmann28558f52016-01-27 16:57:18 +01006851#ifdef CONFIG_PROC_FS
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006852static void seq_mpt_print_ioc_summary(MPT_ADAPTER *ioc, struct seq_file *m, int showlan)
6853{
6854 char expVer[32];
6855
6856 mpt_get_fw_exp_ver(expVer, ioc);
6857
6858 /*
6859 * Shorter summary of attached ioc's...
6860 */
6861 seq_printf(m, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6862 ioc->name,
6863 ioc->prod_name,
6864 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6865 ioc->facts.FWVersion.Word,
6866 expVer,
6867 ioc->facts.NumberOfPorts,
6868 ioc->req_depth);
6869
6870 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6871 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6872 seq_printf(m, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6873 a[5], a[4], a[3], a[2], a[1], a[0]);
6874 }
6875
6876 seq_printf(m, ", IRQ=%d", ioc->pci_irq);
6877
6878 if (!ioc->active)
6879 seq_printf(m, " (disabled)");
6880
6881 seq_putc(m, '\n');
6882}
Arnd Bergmann28558f52016-01-27 16:57:18 +01006883#endif
Alexey Dobriyaneb6edad2010-08-10 18:01:15 -07006884
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306885/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006886 * mpt_set_taskmgmt_in_progress_flag - set flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306887 * @ioc: Pointer to MPT_ADAPTER structure
6888 *
6889 * Returns 0 for SUCCESS or -1 if FAILED.
6890 *
6891 * If -1 is return, then it was not possible to set the flags
6892 **/
6893int
6894mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6895{
6896 unsigned long flags;
6897 int retval;
6898
6899 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6900 if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
6901 (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
6902 retval = -1;
6903 goto out;
6904 }
6905 retval = 0;
6906 ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306907 ioc->taskmgmt_quiesce_io = 1;
6908 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306909 ioc->alt_ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306910 ioc->alt_ioc->taskmgmt_quiesce_io = 1;
6911 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306912 out:
6913 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6914 return retval;
6915}
6916EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
6917
6918/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006919 * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306920 * @ioc: Pointer to MPT_ADAPTER structure
6921 *
6922 **/
6923void
6924mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6925{
6926 unsigned long flags;
6927
6928 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6929 ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306930 ioc->taskmgmt_quiesce_io = 0;
6931 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306932 ioc->alt_ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306933 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
6934 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306935 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6936}
6937EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006938
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306939
6940/**
6941 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6942 * the kernel
6943 * @ioc: Pointer to MPT_ADAPTER structure
6944 *
6945 **/
6946void
6947mpt_halt_firmware(MPT_ADAPTER *ioc)
6948{
6949 u32 ioc_raw_state;
6950
6951 ioc_raw_state = mpt_GetIocState(ioc, 0);
6952
6953 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6954 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6955 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6956 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6957 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6958 } else {
6959 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6960 panic("%s: Firmware is halted due to command timeout\n",
6961 ioc->name);
6962 }
6963}
6964EXPORT_SYMBOL(mpt_halt_firmware);
6965
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306966/**
6967 * mpt_SoftResetHandler - Issues a less expensive reset
6968 * @ioc: Pointer to MPT_ADAPTER structure
6969 * @sleepFlag: Indicates if sleep or schedule must be called.
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306970 *
6971 * Returns 0 for SUCCESS or -1 if FAILED.
6972 *
6973 * Message Unit Reset - instructs the IOC to reset the Reply Post and
6974 * Free FIFO's. All the Message Frames on Reply Free FIFO are discarded.
6975 * All posted buffers are freed, and event notification is turned off.
Lucas De Marchi25985ed2011-03-30 22:57:33 -03006976 * IOC doesn't reply to any outstanding request. This will transfer IOC
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306977 * to READY state.
6978 **/
Joe Lawrence5767d252014-06-25 17:05:49 -04006979static int
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306980mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6981{
6982 int rc;
6983 int ii;
6984 u8 cb_idx;
6985 unsigned long flags;
6986 u32 ioc_state;
6987 unsigned long time_count;
6988
6989 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n",
6990 ioc->name));
6991
6992 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
6993
6994 if (mpt_fwfault_debug)
6995 mpt_halt_firmware(ioc);
6996
6997 if (ioc_state == MPI_IOC_STATE_FAULT ||
6998 ioc_state == MPI_IOC_STATE_RESET) {
6999 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7000 "skipping, either in FAULT or RESET state!\n", ioc->name));
7001 return -1;
7002 }
7003
7004 if (ioc->bus_type == FC) {
7005 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7006 "skipping, because the bus type is FC!\n", ioc->name));
7007 return -1;
7008 }
7009
7010 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7011 if (ioc->ioc_reset_in_progress) {
7012 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7013 return -1;
7014 }
7015 ioc->ioc_reset_in_progress = 1;
7016 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7017
7018 rc = -1;
7019
7020 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7021 if (MptResetHandlers[cb_idx])
7022 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
7023 }
7024
7025 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7026 if (ioc->taskmgmt_in_progress) {
Kashyap, Desaib9a0f872010-06-17 14:42:39 +05307027 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05307028 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7029 return -1;
7030 }
7031 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7032 /* Disable reply interrupts (also blocks FreeQ) */
7033 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
7034 ioc->active = 0;
7035 time_count = jiffies;
7036
7037 rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
7038
7039 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7040 if (MptResetHandlers[cb_idx])
7041 mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
7042 }
7043
7044 if (rc)
7045 goto out;
7046
7047 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
7048 if (ioc_state != MPI_IOC_STATE_READY)
7049 goto out;
7050
7051 for (ii = 0; ii < 5; ii++) {
7052 /* Get IOC facts! Allow 5 retries */
7053 rc = GetIocFacts(ioc, sleepFlag,
7054 MPT_HOSTEVENT_IOC_RECOVER);
7055 if (rc == 0)
7056 break;
7057 if (sleepFlag == CAN_SLEEP)
7058 msleep(100);
7059 else
7060 mdelay(100);
7061 }
7062 if (ii == 5)
7063 goto out;
7064
7065 rc = PrimeIocFifos(ioc);
7066 if (rc != 0)
7067 goto out;
7068
7069 rc = SendIocInit(ioc, sleepFlag);
7070 if (rc != 0)
7071 goto out;
7072
7073 rc = SendEventNotification(ioc, 1, sleepFlag);
7074 if (rc != 0)
7075 goto out;
7076
7077 if (ioc->hard_resets < -1)
7078 ioc->hard_resets++;
7079
7080 /*
7081 * At this point, we know soft reset succeeded.
7082 */
7083
7084 ioc->active = 1;
7085 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
7086
7087 out:
7088 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7089 ioc->ioc_reset_in_progress = 0;
7090 ioc->taskmgmt_quiesce_io = 0;
7091 ioc->taskmgmt_in_progress = 0;
7092 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7093
7094 if (ioc->active) { /* otherwise, hard reset coming */
7095 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7096 if (MptResetHandlers[cb_idx])
7097 mpt_signal_reset(cb_idx, ioc,
7098 MPT_IOC_POST_RESET);
7099 }
7100 }
7101
7102 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7103 "SoftResetHandler: completed (%d seconds): %s\n",
7104 ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,
7105 ((rc == 0) ? "SUCCESS" : "FAILED")));
7106
7107 return rc;
7108}
7109
7110/**
7111 * mpt_Soft_Hard_ResetHandler - Try less expensive reset
7112 * @ioc: Pointer to MPT_ADAPTER structure
7113 * @sleepFlag: Indicates if sleep or schedule must be called.
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05307114 *
7115 * Returns 0 for SUCCESS or -1 if FAILED.
7116 * Try for softreset first, only if it fails go for expensive
7117 * HardReset.
7118 **/
7119int
7120mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag) {
7121 int ret = -1;
7122
7123 ret = mpt_SoftResetHandler(ioc, sleepFlag);
7124 if (ret == 0)
7125 return ret;
7126 ret = mpt_HardResetHandler(ioc, sleepFlag);
7127 return ret;
7128}
7129EXPORT_SYMBOL(mpt_Soft_Hard_ResetHandler);
7130
Linus Torvalds1da177e2005-04-16 15:20:36 -07007131/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7132/*
7133 * Reset Handling
7134 */
7135/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7136/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007137 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07007138 * @ioc: Pointer to MPT_ADAPTER structure
7139 * @sleepFlag: Indicates if sleep or schedule must be called.
7140 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007141 * Issues SCSI Task Management call based on input arg values.
7142 * If TaskMgmt fails, returns associated SCSI request.
7143 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07007144 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
7145 * or a non-interrupt thread. In the former, must not call schedule().
7146 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007147 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07007148 * FW reload/initialization failed.
7149 *
7150 * Returns 0 for SUCCESS or -1 if FAILED.
7151 */
7152int
7153mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
7154{
Kashyap, Desaid1306912009-08-05 12:53:51 +05307155 int rc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307156 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007157 unsigned long flags;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307158 unsigned long time_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007159
Prakash, Sathya436ace72007-07-24 15:42:08 +05307160 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007161#ifdef MFCNT
7162 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
7163 printk("MF count 0x%x !\n", ioc->mfcnt);
7164#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05307165 if (mpt_fwfault_debug)
7166 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007167
7168 /* Reset the adapter. Prevent more than 1 call to
7169 * mpt_do_ioc_recovery at any instant in time.
7170 */
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307171 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7172 if (ioc->ioc_reset_in_progress) {
7173 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05307174 ioc->wait_on_reset_completion = 1;
7175 do {
7176 ssleep(1);
7177 } while (ioc->ioc_reset_in_progress == 1);
7178 ioc->wait_on_reset_completion = 0;
7179 return ioc->reset_status;
7180 }
7181 if (ioc->wait_on_reset_completion) {
7182 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7183 rc = 0;
7184 time_count = jiffies;
7185 goto exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007186 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307187 ioc->ioc_reset_in_progress = 1;
7188 if (ioc->alt_ioc)
7189 ioc->alt_ioc->ioc_reset_in_progress = 1;
7190 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007191
Linus Torvalds1da177e2005-04-16 15:20:36 -07007192
7193 /* The SCSI driver needs to adjust timeouts on all current
7194 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02007195 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007196 * For all other protocol drivers, this is a no-op.
7197 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05307198 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7199 if (MptResetHandlers[cb_idx]) {
7200 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
7201 if (ioc->alt_ioc)
7202 mpt_signal_reset(cb_idx, ioc->alt_ioc,
7203 MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007204 }
7205 }
7206
Kashyap, Desai2f187862009-05-29 16:52:37 +05307207 time_count = jiffies;
7208 rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
7209 if (rc != 0) {
7210 printk(KERN_WARNING MYNAM
Kei Tokunaga97009a22010-06-22 19:01:51 +09007211 ": WARNING - (%d) Cannot recover %s, doorbell=0x%08x\n",
7212 rc, ioc->name, mpt_GetIocState(ioc, 0));
Kashyap, Desai2f187862009-05-29 16:52:37 +05307213 } else {
7214 if (ioc->hard_resets < -1)
7215 ioc->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007216 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007217
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307218 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7219 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307220 ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307221 ioc->taskmgmt_in_progress = 0;
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05307222 ioc->reset_status = rc;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307223 if (ioc->alt_ioc) {
7224 ioc->alt_ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307225 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307226 ioc->alt_ioc->taskmgmt_in_progress = 0;
7227 }
7228 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007229
Kashyap, Desaid1306912009-08-05 12:53:51 +05307230 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7231 if (MptResetHandlers[cb_idx]) {
7232 mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
7233 if (ioc->alt_ioc)
7234 mpt_signal_reset(cb_idx,
7235 ioc->alt_ioc, MPT_IOC_POST_RESET);
7236 }
7237 }
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05307238exit:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307239 dtmprintk(ioc,
7240 printk(MYIOC_s_DEBUG_FMT
7241 "HardResetHandler: completed (%d seconds): %s\n", ioc->name,
7242 jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?
7243 "SUCCESS" : "FAILED")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007244
7245 return rc;
7246}
7247
Kashyap, Desai2f187862009-05-29 16:52:37 +05307248#ifdef CONFIG_FUSION_LOGGING
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007249static void
Kashyap, Desai2f187862009-05-29 16:52:37 +05307250mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007251{
Eric Moore509e5e52006-04-26 13:22:37 -06007252 char *ds = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307253 u32 evData0;
7254 int ii;
7255 u8 event;
7256 char *evStr = ioc->evStr;
7257
7258 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7259 evData0 = le32_to_cpu(pEventReply->Data[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007260
7261 switch(event) {
7262 case MPI_EVENT_NONE:
7263 ds = "None";
7264 break;
7265 case MPI_EVENT_LOG_DATA:
7266 ds = "Log Data";
7267 break;
7268 case MPI_EVENT_STATE_CHANGE:
7269 ds = "State Change";
7270 break;
7271 case MPI_EVENT_UNIT_ATTENTION:
7272 ds = "Unit Attention";
7273 break;
7274 case MPI_EVENT_IOC_BUS_RESET:
7275 ds = "IOC Bus Reset";
7276 break;
7277 case MPI_EVENT_EXT_BUS_RESET:
7278 ds = "External Bus Reset";
7279 break;
7280 case MPI_EVENT_RESCAN:
7281 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007282 break;
7283 case MPI_EVENT_LINK_STATUS_CHANGE:
7284 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
7285 ds = "Link Status(FAILURE) Change";
7286 else
7287 ds = "Link Status(ACTIVE) Change";
7288 break;
7289 case MPI_EVENT_LOOP_STATE_CHANGE:
7290 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
7291 ds = "Loop State(LIP) Change";
7292 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Kashyap, Desai2f187862009-05-29 16:52:37 +05307293 ds = "Loop State(LPE) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007294 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05307295 ds = "Loop State(LPB) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007296 break;
7297 case MPI_EVENT_LOGOUT:
7298 ds = "Logout";
7299 break;
7300 case MPI_EVENT_EVENT_CHANGE:
7301 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06007302 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007303 else
Eric Moore4f766dc2006-07-11 17:24:07 -06007304 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007305 break;
7306 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007307 {
7308 u8 ReasonCode = (u8)(evData0 >> 16);
7309 switch (ReasonCode) {
7310 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
7311 ds = "Integrated Raid: Volume Created";
7312 break;
7313 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
7314 ds = "Integrated Raid: Volume Deleted";
7315 break;
7316 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
7317 ds = "Integrated Raid: Volume Settings Changed";
7318 break;
7319 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
7320 ds = "Integrated Raid: Volume Status Changed";
7321 break;
7322 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
7323 ds = "Integrated Raid: Volume Physdisk Changed";
7324 break;
7325 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
7326 ds = "Integrated Raid: Physdisk Created";
7327 break;
7328 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
7329 ds = "Integrated Raid: Physdisk Deleted";
7330 break;
7331 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
7332 ds = "Integrated Raid: Physdisk Settings Changed";
7333 break;
7334 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
7335 ds = "Integrated Raid: Physdisk Status Changed";
7336 break;
7337 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
7338 ds = "Integrated Raid: Domain Validation Needed";
7339 break;
7340 case MPI_EVENT_RAID_RC_SMART_DATA :
7341 ds = "Integrated Raid; Smart Data";
7342 break;
7343 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
7344 ds = "Integrated Raid: Replace Action Started";
7345 break;
7346 default:
7347 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007348 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007349 }
7350 break;
7351 }
7352 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
7353 ds = "SCSI Device Status Change";
7354 break;
7355 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
7356 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007357 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007358 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007359 u8 ReasonCode = (u8)(evData0 >> 16);
7360 switch (ReasonCode) {
7361 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007362 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007363 "SAS Device Status Change: Added: "
7364 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007365 break;
7366 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06007367 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007368 "SAS Device Status Change: Deleted: "
7369 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007370 break;
7371 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06007372 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007373 "SAS Device Status Change: SMART Data: "
7374 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007375 break;
7376 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007377 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007378 "SAS Device Status Change: No Persistancy: "
7379 "id=%d channel=%d", id, channel);
7380 break;
7381 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
7382 snprintf(evStr, EVENT_DESCR_STR_SZ,
7383 "SAS Device Status Change: Unsupported Device "
7384 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007385 break;
7386 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
7387 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007388 "SAS Device Status Change: Internal Device "
7389 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007390 break;
7391 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
7392 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007393 "SAS Device Status Change: Internal Task "
7394 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007395 break;
7396 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
7397 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007398 "SAS Device Status Change: Internal Abort "
7399 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007400 break;
7401 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
7402 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007403 "SAS Device Status Change: Internal Clear "
7404 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007405 break;
7406 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
7407 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007408 "SAS Device Status Change: Internal Query "
7409 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007410 break;
7411 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007412 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007413 "SAS Device Status Change: Unknown: "
7414 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06007415 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007416 }
7417 break;
7418 }
7419 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
7420 ds = "Bus Timer Expired";
7421 break;
7422 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07007423 {
7424 u16 curr_depth = (u16)(evData0 >> 16);
7425 u8 channel = (u8)(evData0 >> 8);
7426 u8 id = (u8)(evData0);
7427
7428 snprintf(evStr, EVENT_DESCR_STR_SZ,
7429 "Queue Full: channel=%d id=%d depth=%d",
7430 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007431 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07007432 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007433 case MPI_EVENT_SAS_SES:
7434 ds = "SAS SES Event";
7435 break;
7436 case MPI_EVENT_PERSISTENT_TABLE_FULL:
7437 ds = "Persistent Table Full";
7438 break;
7439 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07007440 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007441 u8 LinkRates = (u8)(evData0 >> 8);
7442 u8 PhyNumber = (u8)(evData0);
7443 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
7444 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
7445 switch (LinkRates) {
7446 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06007447 snprintf(evStr, EVENT_DESCR_STR_SZ,
7448 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007449 " Rate Unknown",PhyNumber);
7450 break;
7451 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06007452 snprintf(evStr, EVENT_DESCR_STR_SZ,
7453 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007454 " Phy Disabled",PhyNumber);
7455 break;
7456 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06007457 snprintf(evStr, EVENT_DESCR_STR_SZ,
7458 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007459 " Failed Speed Nego",PhyNumber);
7460 break;
7461 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06007462 snprintf(evStr, EVENT_DESCR_STR_SZ,
7463 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007464 " Sata OOB Completed",PhyNumber);
7465 break;
7466 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06007467 snprintf(evStr, EVENT_DESCR_STR_SZ,
7468 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007469 " Rate 1.5 Gbps",PhyNumber);
7470 break;
7471 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06007472 snprintf(evStr, EVENT_DESCR_STR_SZ,
7473 "SAS PHY Link Status: Phy=%d:"
Kashyap, Desaid75733d2011-02-10 11:50:39 +05307474 " Rate 3.0 Gbps", PhyNumber);
7475 break;
7476 case MPI_EVENT_SAS_PLS_LR_RATE_6_0:
7477 snprintf(evStr, EVENT_DESCR_STR_SZ,
7478 "SAS PHY Link Status: Phy=%d:"
7479 " Rate 6.0 Gbps", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007480 break;
7481 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007482 snprintf(evStr, EVENT_DESCR_STR_SZ,
7483 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007484 break;
7485 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007486 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007487 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007488 case MPI_EVENT_SAS_DISCOVERY_ERROR:
7489 ds = "SAS Discovery Error";
7490 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007491 case MPI_EVENT_IR_RESYNC_UPDATE:
7492 {
7493 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06007494 snprintf(evStr, EVENT_DESCR_STR_SZ,
7495 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07007496 break;
7497 }
7498 case MPI_EVENT_IR2:
7499 {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307500 u8 id = (u8)(evData0);
7501 u8 channel = (u8)(evData0 >> 8);
7502 u8 phys_num = (u8)(evData0 >> 24);
Moore, Eric3a892be2006-03-14 09:14:03 -07007503 u8 ReasonCode = (u8)(evData0 >> 16);
Kashyap, Desai2f187862009-05-29 16:52:37 +05307504
Moore, Eric3a892be2006-03-14 09:14:03 -07007505 switch (ReasonCode) {
7506 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307507 snprintf(evStr, EVENT_DESCR_STR_SZ,
7508 "IR2: LD State Changed: "
7509 "id=%d channel=%d phys_num=%d",
7510 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007511 break;
7512 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307513 snprintf(evStr, EVENT_DESCR_STR_SZ,
7514 "IR2: PD State Changed "
7515 "id=%d channel=%d phys_num=%d",
7516 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007517 break;
7518 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307519 snprintf(evStr, EVENT_DESCR_STR_SZ,
7520 "IR2: Bad Block Table Full: "
7521 "id=%d channel=%d phys_num=%d",
7522 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007523 break;
7524 case MPI_EVENT_IR2_RC_PD_INSERTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307525 snprintf(evStr, EVENT_DESCR_STR_SZ,
7526 "IR2: PD Inserted: "
7527 "id=%d channel=%d phys_num=%d",
7528 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007529 break;
7530 case MPI_EVENT_IR2_RC_PD_REMOVED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307531 snprintf(evStr, EVENT_DESCR_STR_SZ,
7532 "IR2: PD Removed: "
7533 "id=%d channel=%d phys_num=%d",
7534 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007535 break;
7536 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307537 snprintf(evStr, EVENT_DESCR_STR_SZ,
7538 "IR2: Foreign CFG Detected: "
7539 "id=%d channel=%d phys_num=%d",
7540 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007541 break;
7542 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307543 snprintf(evStr, EVENT_DESCR_STR_SZ,
7544 "IR2: Rebuild Medium Error: "
7545 "id=%d channel=%d phys_num=%d",
7546 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007547 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05307548 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
7549 snprintf(evStr, EVENT_DESCR_STR_SZ,
7550 "IR2: Dual Port Added: "
7551 "id=%d channel=%d phys_num=%d",
7552 id, channel, phys_num);
7553 break;
7554 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
7555 snprintf(evStr, EVENT_DESCR_STR_SZ,
7556 "IR2: Dual Port Removed: "
7557 "id=%d channel=%d phys_num=%d",
7558 id, channel, phys_num);
7559 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007560 default:
7561 ds = "IR2";
7562 break;
7563 }
7564 break;
7565 }
7566 case MPI_EVENT_SAS_DISCOVERY:
7567 {
7568 if (evData0)
7569 ds = "SAS Discovery: Start";
7570 else
7571 ds = "SAS Discovery: Stop";
7572 break;
7573 }
7574 case MPI_EVENT_LOG_ENTRY_ADDED:
7575 ds = "SAS Log Entry Added";
7576 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007577
Eric Moorec6c727a2007-01-29 09:44:54 -07007578 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
7579 {
7580 u8 phy_num = (u8)(evData0);
7581 u8 port_num = (u8)(evData0 >> 8);
7582 u8 port_width = (u8)(evData0 >> 16);
7583 u8 primative = (u8)(evData0 >> 24);
7584 snprintf(evStr, EVENT_DESCR_STR_SZ,
7585 "SAS Broadcase Primative: phy=%d port=%d "
7586 "width=%d primative=0x%02x",
7587 phy_num, port_num, port_width, primative);
7588 break;
7589 }
7590
7591 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7592 {
7593 u8 reason = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007594
Kashyap, Desai2f187862009-05-29 16:52:37 +05307595 switch (reason) {
7596 case MPI_EVENT_SAS_INIT_RC_ADDED:
7597 ds = "SAS Initiator Status Change: Added";
7598 break;
7599 case MPI_EVENT_SAS_INIT_RC_REMOVED:
7600 ds = "SAS Initiator Status Change: Deleted";
7601 break;
7602 default:
7603 ds = "SAS Initiator Status Change";
7604 break;
7605 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007606 break;
7607 }
7608
7609 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7610 {
7611 u8 max_init = (u8)(evData0);
7612 u8 current_init = (u8)(evData0 >> 8);
7613
7614 snprintf(evStr, EVENT_DESCR_STR_SZ,
7615 "SAS Initiator Device Table Overflow: max initiators=%02d "
7616 "current initators=%02d",
7617 max_init, current_init);
7618 break;
7619 }
7620 case MPI_EVENT_SAS_SMP_ERROR:
7621 {
7622 u8 status = (u8)(evData0);
7623 u8 port_num = (u8)(evData0 >> 8);
7624 u8 result = (u8)(evData0 >> 16);
7625
7626 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7627 snprintf(evStr, EVENT_DESCR_STR_SZ,
7628 "SAS SMP Error: port=%d result=0x%02x",
7629 port_num, result);
7630 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7631 snprintf(evStr, EVENT_DESCR_STR_SZ,
7632 "SAS SMP Error: port=%d : CRC Error",
7633 port_num);
7634 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7635 snprintf(evStr, EVENT_DESCR_STR_SZ,
7636 "SAS SMP Error: port=%d : Timeout",
7637 port_num);
7638 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7639 snprintf(evStr, EVENT_DESCR_STR_SZ,
7640 "SAS SMP Error: port=%d : No Destination",
7641 port_num);
7642 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7643 snprintf(evStr, EVENT_DESCR_STR_SZ,
7644 "SAS SMP Error: port=%d : Bad Destination",
7645 port_num);
7646 else
7647 snprintf(evStr, EVENT_DESCR_STR_SZ,
7648 "SAS SMP Error: port=%d : status=0x%02x",
7649 port_num, status);
7650 break;
7651 }
7652
Kashyap, Desai2f187862009-05-29 16:52:37 +05307653 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
7654 {
7655 u8 reason = (u8)(evData0);
7656
7657 switch (reason) {
7658 case MPI_EVENT_SAS_EXP_RC_ADDED:
7659 ds = "Expander Status Change: Added";
7660 break;
7661 case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
7662 ds = "Expander Status Change: Deleted";
7663 break;
7664 default:
7665 ds = "Expander Status Change";
7666 break;
7667 }
7668 break;
7669 }
7670
Linus Torvalds1da177e2005-04-16 15:20:36 -07007671 /*
7672 * MPT base "custom" events may be added here...
7673 */
7674 default:
7675 ds = "Unknown";
7676 break;
7677 }
Eric Moore509e5e52006-04-26 13:22:37 -06007678 if (ds)
7679 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007680
Kashyap, Desai2f187862009-05-29 16:52:37 +05307681
7682 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7683 "MPT event:(%02Xh) : %s\n",
7684 ioc->name, event, evStr));
7685
7686 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
7687 ": Event data:\n"));
7688 for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
7689 devtverboseprintk(ioc, printk(" %08x",
7690 le32_to_cpu(pEventReply->Data[ii])));
7691 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
7692}
7693#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007694/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007695/**
7696 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007697 * @ioc: Pointer to MPT_ADAPTER structure
7698 * @pEventReply: Pointer to EventNotification reply frame
7699 * @evHandlers: Pointer to integer, number of event handlers
7700 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007701 * Routes a received EventNotificationReply to all currently registered
7702 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007703 * Returns sum of event handlers return values.
7704 */
7705static int
7706ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7707{
7708 u16 evDataLen;
7709 u32 evData0 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007710 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307711 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007712 int r = 0;
7713 int handlers = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007714 u8 event;
7715
7716 /*
7717 * Do platform normalization of values
7718 */
7719 event = le32_to_cpu(pEventReply->Event) & 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007720 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7721 if (evDataLen) {
7722 evData0 = le32_to_cpu(pEventReply->Data[0]);
7723 }
7724
Prakash, Sathya436ace72007-07-24 15:42:08 +05307725#ifdef CONFIG_FUSION_LOGGING
Kashyap, Desai2f187862009-05-29 16:52:37 +05307726 if (evDataLen)
7727 mpt_display_event_info(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007728#endif
7729
7730 /*
7731 * Do general / base driver event processing
7732 */
7733 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007734 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7735 if (evDataLen) {
7736 u8 evState = evData0 & 0xFF;
7737
7738 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7739
7740 /* Update EventState field in cached IocFacts */
7741 if (ioc->facts.Function) {
7742 ioc->facts.EventState = evState;
7743 }
7744 }
7745 break;
Moore, Ericece50912006-01-16 18:53:19 -07007746 case MPI_EVENT_INTEGRATED_RAID:
7747 mptbase_raid_process_event_data(ioc,
7748 (MpiEventDataRaid_t *)pEventReply->Data);
7749 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007750 default:
7751 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007752 }
7753
7754 /*
7755 * Should this event be logged? Events are written sequentially.
7756 * When buffer is full, start again at the top.
7757 */
7758 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7759 int idx;
7760
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007761 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007762
7763 ioc->events[idx].event = event;
7764 ioc->events[idx].eventContext = ioc->eventContext;
7765
7766 for (ii = 0; ii < 2; ii++) {
7767 if (ii < evDataLen)
7768 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7769 else
7770 ioc->events[idx].data[ii] = 0;
7771 }
7772
7773 ioc->eventContext++;
7774 }
7775
7776
7777 /*
7778 * Call each currently registered protocol event handler.
7779 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007780 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307781 if (MptEvHandlers[cb_idx]) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307782 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7783 "Routing Event to event handler #%d\n",
7784 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307785 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007786 handlers++;
7787 }
7788 }
7789 /* FIXME? Examine results here? */
7790
7791 /*
7792 * If needed, send (a single) EventAck.
7793 */
7794 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307795 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007796 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007797 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307798 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007799 ioc->name, ii));
7800 }
7801 }
7802
7803 *evHandlers = handlers;
7804 return r;
7805}
7806
7807/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007808/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007809 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7810 * @ioc: Pointer to MPT_ADAPTER structure
7811 * @log_info: U32 LogInfo reply word from the IOC
7812 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007813 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007814 */
7815static void
7816mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7817{
Eric Moore7c431e52007-06-13 16:34:36 -06007818 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007819
Eric Moore7c431e52007-06-13 16:34:36 -06007820 switch (log_info & 0xFF000000) {
7821 case MPI_IOCLOGINFO_FC_INIT_BASE:
7822 desc = "FCP Initiator";
7823 break;
7824 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7825 desc = "FCP Target";
7826 break;
7827 case MPI_IOCLOGINFO_FC_LAN_BASE:
7828 desc = "LAN";
7829 break;
7830 case MPI_IOCLOGINFO_FC_MSG_BASE:
7831 desc = "MPI Message Layer";
7832 break;
7833 case MPI_IOCLOGINFO_FC_LINK_BASE:
7834 desc = "FC Link";
7835 break;
7836 case MPI_IOCLOGINFO_FC_CTX_BASE:
7837 desc = "Context Manager";
7838 break;
7839 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7840 desc = "Invalid Field Offset";
7841 break;
7842 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7843 desc = "State Change Info";
7844 break;
7845 }
7846
7847 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7848 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007849}
7850
7851/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007852/**
Moore, Eric335a9412006-01-17 17:06:23 -07007853 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007854 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007855 * @log_info: U32 LogInfo word from the IOC
7856 *
7857 * Refer to lsi/sp_log.h.
7858 */
7859static void
Moore, Eric335a9412006-01-17 17:06:23 -07007860mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007861{
7862 u32 info = log_info & 0x00FF0000;
7863 char *desc = "unknown";
7864
7865 switch (info) {
7866 case 0x00010000:
7867 desc = "bug! MID not found";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007868 break;
7869
7870 case 0x00020000:
7871 desc = "Parity Error";
7872 break;
7873
7874 case 0x00030000:
7875 desc = "ASYNC Outbound Overrun";
7876 break;
7877
7878 case 0x00040000:
7879 desc = "SYNC Offset Error";
7880 break;
7881
7882 case 0x00050000:
7883 desc = "BM Change";
7884 break;
7885
7886 case 0x00060000:
7887 desc = "Msg In Overflow";
7888 break;
7889
7890 case 0x00070000:
7891 desc = "DMA Error";
7892 break;
7893
7894 case 0x00080000:
7895 desc = "Outbound DMA Overrun";
7896 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007897
Linus Torvalds1da177e2005-04-16 15:20:36 -07007898 case 0x00090000:
7899 desc = "Task Management";
7900 break;
7901
7902 case 0x000A0000:
7903 desc = "Device Problem";
7904 break;
7905
7906 case 0x000B0000:
7907 desc = "Invalid Phase Change";
7908 break;
7909
7910 case 0x000C0000:
7911 desc = "Untagged Table Size";
7912 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007913
Linus Torvalds1da177e2005-04-16 15:20:36 -07007914 }
7915
7916 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7917}
7918
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007919/* strings for sas loginfo */
7920 static char *originator_str[] = {
7921 "IOP", /* 00h */
7922 "PL", /* 01h */
7923 "IR" /* 02h */
7924 };
7925 static char *iop_code_str[] = {
7926 NULL, /* 00h */
7927 "Invalid SAS Address", /* 01h */
7928 NULL, /* 02h */
7929 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007930 "Diag Message Error", /* 04h */
7931 "Task Terminated", /* 05h */
7932 "Enclosure Management", /* 06h */
7933 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007934 };
7935 static char *pl_code_str[] = {
7936 NULL, /* 00h */
7937 "Open Failure", /* 01h */
7938 "Invalid Scatter Gather List", /* 02h */
7939 "Wrong Relative Offset or Frame Length", /* 03h */
7940 "Frame Transfer Error", /* 04h */
7941 "Transmit Frame Connected Low", /* 05h */
7942 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7943 "SATA Read Log Receive Data Error", /* 07h */
7944 "SATA NCQ Fail All Commands After Error", /* 08h */
7945 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7946 "Receive Frame Invalid Message", /* 0Ah */
7947 "Receive Context Message Valid Error", /* 0Bh */
7948 "Receive Frame Current Frame Error", /* 0Ch */
7949 "SATA Link Down", /* 0Dh */
7950 "Discovery SATA Init W IOS", /* 0Eh */
7951 "Config Invalid Page", /* 0Fh */
7952 "Discovery SATA Init Timeout", /* 10h */
7953 "Reset", /* 11h */
7954 "Abort", /* 12h */
7955 "IO Not Yet Executed", /* 13h */
7956 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007957 "Persistent Reservation Out Not Affiliation "
7958 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007959 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007960 "IO Device Missing Delay Retry", /* 17h */
Lucas De Marchi25985ed2011-03-30 22:57:33 -03007961 "IO Cancelled Due to Receive Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007962 NULL, /* 19h */
7963 NULL, /* 1Ah */
7964 NULL, /* 1Bh */
7965 NULL, /* 1Ch */
7966 NULL, /* 1Dh */
7967 NULL, /* 1Eh */
7968 NULL, /* 1Fh */
7969 "Enclosure Management" /* 20h */
7970 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007971 static char *ir_code_str[] = {
7972 "Raid Action Error", /* 00h */
7973 NULL, /* 00h */
7974 NULL, /* 01h */
7975 NULL, /* 02h */
7976 NULL, /* 03h */
7977 NULL, /* 04h */
7978 NULL, /* 05h */
7979 NULL, /* 06h */
7980 NULL /* 07h */
7981 };
7982 static char *raid_sub_code_str[] = {
7983 NULL, /* 00h */
7984 "Volume Creation Failed: Data Passed too "
7985 "Large", /* 01h */
7986 "Volume Creation Failed: Duplicate Volumes "
7987 "Attempted", /* 02h */
7988 "Volume Creation Failed: Max Number "
7989 "Supported Volumes Exceeded", /* 03h */
7990 "Volume Creation Failed: DMA Error", /* 04h */
7991 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7992 "Volume Creation Failed: Error Reading "
7993 "MFG Page 4", /* 06h */
7994 "Volume Creation Failed: Creating Internal "
7995 "Structures", /* 07h */
7996 NULL, /* 08h */
7997 NULL, /* 09h */
7998 NULL, /* 0Ah */
7999 NULL, /* 0Bh */
8000 NULL, /* 0Ch */
8001 NULL, /* 0Dh */
8002 NULL, /* 0Eh */
8003 NULL, /* 0Fh */
8004 "Activation failed: Already Active Volume", /* 10h */
8005 "Activation failed: Unsupported Volume Type", /* 11h */
8006 "Activation failed: Too Many Active Volumes", /* 12h */
8007 "Activation failed: Volume ID in Use", /* 13h */
8008 "Activation failed: Reported Failure", /* 14h */
8009 "Activation failed: Importing a Volume", /* 15h */
8010 NULL, /* 16h */
8011 NULL, /* 17h */
8012 NULL, /* 18h */
8013 NULL, /* 19h */
8014 NULL, /* 1Ah */
8015 NULL, /* 1Bh */
8016 NULL, /* 1Ch */
8017 NULL, /* 1Dh */
8018 NULL, /* 1Eh */
8019 NULL, /* 1Fh */
8020 "Phys Disk failed: Too Many Phys Disks", /* 20h */
8021 "Phys Disk failed: Data Passed too Large", /* 21h */
8022 "Phys Disk failed: DMA Error", /* 22h */
8023 "Phys Disk failed: Invalid <channel:id>", /* 23h */
8024 "Phys Disk failed: Creating Phys Disk Config "
8025 "Page", /* 24h */
8026 NULL, /* 25h */
8027 NULL, /* 26h */
8028 NULL, /* 27h */
8029 NULL, /* 28h */
8030 NULL, /* 29h */
8031 NULL, /* 2Ah */
8032 NULL, /* 2Bh */
8033 NULL, /* 2Ch */
8034 NULL, /* 2Dh */
8035 NULL, /* 2Eh */
8036 NULL, /* 2Fh */
8037 "Compatibility Error: IR Disabled", /* 30h */
Uwe Kleine-Königb5950762010-11-01 15:38:34 -04008038 "Compatibility Error: Inquiry Command Failed", /* 31h */
Eric Moorec6c727a2007-01-29 09:44:54 -07008039 "Compatibility Error: Device not Direct Access "
8040 "Device ", /* 32h */
8041 "Compatibility Error: Removable Device Found", /* 33h */
8042 "Compatibility Error: Device SCSI Version not "
8043 "2 or Higher", /* 34h */
8044 "Compatibility Error: SATA Device, 48 BIT LBA "
8045 "not Supported", /* 35h */
8046 "Compatibility Error: Device doesn't have "
8047 "512 Byte Block Sizes", /* 36h */
8048 "Compatibility Error: Volume Type Check Failed", /* 37h */
8049 "Compatibility Error: Volume Type is "
8050 "Unsupported by FW", /* 38h */
8051 "Compatibility Error: Disk Drive too Small for "
8052 "use in Volume", /* 39h */
8053 "Compatibility Error: Phys Disk for Create "
8054 "Volume not Found", /* 3Ah */
8055 "Compatibility Error: Too Many or too Few "
8056 "Disks for Volume Type", /* 3Bh */
8057 "Compatibility Error: Disk stripe Sizes "
8058 "Must be 64KB", /* 3Ch */
8059 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
8060 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008061
8062/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008063/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008064 * mpt_sas_log_info - Log information returned from SAS IOC.
8065 * @ioc: Pointer to MPT_ADAPTER structure
8066 * @log_info: U32 LogInfo reply word from the IOC
Randy Dunlapfc58fb12010-08-14 13:05:57 -07008067 * @cb_idx: callback function's handle
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008068 *
8069 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008070 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008071static void
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308072mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info, u8 cb_idx)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008073{
8074union loginfo_type {
8075 u32 loginfo;
8076 struct {
8077 u32 subcode:16;
8078 u32 code:8;
8079 u32 originator:4;
8080 u32 bus_type:4;
8081 }dw;
8082};
8083 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07008084 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008085 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07008086 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008087
8088 sas_loginfo.loginfo = log_info;
8089 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008090 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008091 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07008092
8093 originator_desc = originator_str[sas_loginfo.dw.originator];
8094
8095 switch (sas_loginfo.dw.originator) {
8096
8097 case 0: /* IOP */
8098 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008099 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008100 code_desc = iop_code_str[sas_loginfo.dw.code];
8101 break;
8102 case 1: /* PL */
8103 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008104 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008105 code_desc = pl_code_str[sas_loginfo.dw.code];
8106 break;
8107 case 2: /* IR */
8108 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008109 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008110 break;
8111 code_desc = ir_code_str[sas_loginfo.dw.code];
8112 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008113 ARRAY_SIZE(raid_sub_code_str))
Julia Lawall081f4f42010-08-05 22:27:14 +02008114 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07008115 if (sas_loginfo.dw.code == 0)
8116 sub_code_desc =
8117 raid_sub_code_str[sas_loginfo.dw.subcode];
8118 break;
8119 default:
8120 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008121 }
8122
Eric Moorec6c727a2007-01-29 09:44:54 -07008123 if (sub_code_desc != NULL)
8124 printk(MYIOC_s_INFO_FMT
8125 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308126 " SubCode={%s} cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008127 ioc->name, log_info, originator_desc, code_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308128 sub_code_desc, MptCallbacksName[cb_idx]);
Eric Moorec6c727a2007-01-29 09:44:54 -07008129 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008130 printk(MYIOC_s_INFO_FMT
8131 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308132 " SubCode(0x%04x) cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008133 ioc->name, log_info, originator_desc, code_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308134 sas_loginfo.dw.subcode, MptCallbacksName[cb_idx]);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008135 else
8136 printk(MYIOC_s_INFO_FMT
8137 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308138 " SubCode(0x%04x) cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008139 ioc->name, log_info, originator_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308140 sas_loginfo.dw.code, sas_loginfo.dw.subcode,
8141 MptCallbacksName[cb_idx]);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008142}
8143
Linus Torvalds1da177e2005-04-16 15:20:36 -07008144/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008145/**
Eric Moorec6c727a2007-01-29 09:44:54 -07008146 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
8147 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08008148 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07008149 * @mf: Pointer to MPT request frame
8150 *
8151 * Refer to lsi/mpi.h.
8152 **/
8153static void
8154mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
8155{
8156 Config_t *pReq = (Config_t *)mf;
8157 char extend_desc[EVENT_DESCR_STR_SZ];
8158 char *desc = NULL;
8159 u32 form;
8160 u8 page_type;
8161
8162 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
8163 page_type = pReq->ExtPageType;
8164 else
8165 page_type = pReq->Header.PageType;
8166
8167 /*
8168 * ignore invalid page messages for GET_NEXT_HANDLE
8169 */
8170 form = le32_to_cpu(pReq->PageAddress);
8171 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
8172 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
8173 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
8174 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
8175 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
8176 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
8177 return;
8178 }
8179 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
8180 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
8181 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
8182 return;
8183 }
8184
8185 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
8186 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
8187 page_type, pReq->Header.PageNumber, pReq->Action, form);
8188
8189 switch (ioc_status) {
8190
8191 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8192 desc = "Config Page Invalid Action";
8193 break;
8194
8195 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8196 desc = "Config Page Invalid Type";
8197 break;
8198
8199 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8200 desc = "Config Page Invalid Page";
8201 break;
8202
8203 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8204 desc = "Config Page Invalid Data";
8205 break;
8206
8207 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8208 desc = "Config Page No Defaults";
8209 break;
8210
8211 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
8212 desc = "Config Page Can't Commit";
8213 break;
8214 }
8215
8216 if (!desc)
8217 return;
8218
Eric Moore29dd3602007-09-14 18:46:51 -06008219 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
8220 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07008221}
8222
8223/**
8224 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07008225 * @ioc: Pointer to MPT_ADAPTER structure
8226 * @ioc_status: U32 IOCStatus word from IOC
8227 * @mf: Pointer to MPT request frame
8228 *
8229 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008230 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07008231static void
Eric Moorec6c727a2007-01-29 09:44:54 -07008232mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008233{
8234 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06008235 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008236
8237 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07008238
8239/****************************************************************************/
8240/* Common IOCStatus values for all replies */
8241/****************************************************************************/
8242
Linus Torvalds1da177e2005-04-16 15:20:36 -07008243 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
8244 desc = "Invalid Function";
8245 break;
8246
8247 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
8248 desc = "Busy";
8249 break;
8250
8251 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
8252 desc = "Invalid SGL";
8253 break;
8254
8255 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
8256 desc = "Internal Error";
8257 break;
8258
8259 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
8260 desc = "Reserved";
8261 break;
8262
8263 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
8264 desc = "Insufficient Resources";
8265 break;
8266
8267 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
8268 desc = "Invalid Field";
8269 break;
8270
8271 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
8272 desc = "Invalid State";
8273 break;
8274
Eric Moorec6c727a2007-01-29 09:44:54 -07008275/****************************************************************************/
8276/* Config IOCStatus values */
8277/****************************************************************************/
8278
Linus Torvalds1da177e2005-04-16 15:20:36 -07008279 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8280 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8281 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8282 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8283 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8284 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008285 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008286 break;
8287
Eric Moorec6c727a2007-01-29 09:44:54 -07008288/****************************************************************************/
8289/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
8290/* */
8291/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
8292/* */
8293/****************************************************************************/
8294
Linus Torvalds1da177e2005-04-16 15:20:36 -07008295 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008296 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008297 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
8298 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
8299 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
8300 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008301 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008302 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008303 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008304 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008305 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008306 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07008307 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008308 break;
8309
Eric Moorec6c727a2007-01-29 09:44:54 -07008310/****************************************************************************/
8311/* SCSI Target values */
8312/****************************************************************************/
8313
8314 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
8315 desc = "Target: Priority IO";
8316 break;
8317
8318 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
8319 desc = "Target: Invalid Port";
8320 break;
8321
8322 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
8323 desc = "Target Invalid IO Index:";
8324 break;
8325
8326 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
8327 desc = "Target: Aborted";
8328 break;
8329
8330 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
8331 desc = "Target: No Conn Retryable";
8332 break;
8333
8334 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
8335 desc = "Target: No Connection";
8336 break;
8337
8338 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
8339 desc = "Target: Transfer Count Mismatch";
8340 break;
8341
8342 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
8343 desc = "Target: STS Data not Sent";
8344 break;
8345
8346 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
8347 desc = "Target: Data Offset Error";
8348 break;
8349
8350 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
8351 desc = "Target: Too Much Write Data";
8352 break;
8353
8354 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
8355 desc = "Target: IU Too Short";
8356 break;
8357
8358 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
8359 desc = "Target: ACK NAK Timeout";
8360 break;
8361
8362 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
8363 desc = "Target: Nak Received";
8364 break;
8365
8366/****************************************************************************/
8367/* Fibre Channel Direct Access values */
8368/****************************************************************************/
8369
8370 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
8371 desc = "FC: Aborted";
8372 break;
8373
8374 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
8375 desc = "FC: RX ID Invalid";
8376 break;
8377
8378 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
8379 desc = "FC: DID Invalid";
8380 break;
8381
8382 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
8383 desc = "FC: Node Logged Out";
8384 break;
8385
8386 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
8387 desc = "FC: Exchange Canceled";
8388 break;
8389
8390/****************************************************************************/
8391/* LAN values */
8392/****************************************************************************/
8393
8394 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
8395 desc = "LAN: Device not Found";
8396 break;
8397
8398 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
8399 desc = "LAN: Device Failure";
8400 break;
8401
8402 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
8403 desc = "LAN: Transmit Error";
8404 break;
8405
8406 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
8407 desc = "LAN: Transmit Aborted";
8408 break;
8409
8410 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
8411 desc = "LAN: Receive Error";
8412 break;
8413
8414 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
8415 desc = "LAN: Receive Aborted";
8416 break;
8417
8418 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
8419 desc = "LAN: Partial Packet";
8420 break;
8421
8422 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
8423 desc = "LAN: Canceled";
8424 break;
8425
8426/****************************************************************************/
8427/* Serial Attached SCSI values */
8428/****************************************************************************/
8429
8430 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
8431 desc = "SAS: SMP Request Failed";
8432 break;
8433
8434 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
8435 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07008436 break;
8437
8438 default:
8439 desc = "Others";
8440 break;
8441 }
Eric Moorec6c727a2007-01-29 09:44:54 -07008442
8443 if (!desc)
8444 return;
8445
Eric Moore29dd3602007-09-14 18:46:51 -06008446 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
8447 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008448}
8449
8450/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008451EXPORT_SYMBOL(mpt_attach);
8452EXPORT_SYMBOL(mpt_detach);
8453#ifdef CONFIG_PM
8454EXPORT_SYMBOL(mpt_resume);
8455EXPORT_SYMBOL(mpt_suspend);
8456#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07008457EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008458EXPORT_SYMBOL(mpt_register);
8459EXPORT_SYMBOL(mpt_deregister);
8460EXPORT_SYMBOL(mpt_event_register);
8461EXPORT_SYMBOL(mpt_event_deregister);
8462EXPORT_SYMBOL(mpt_reset_register);
8463EXPORT_SYMBOL(mpt_reset_deregister);
8464EXPORT_SYMBOL(mpt_device_driver_register);
8465EXPORT_SYMBOL(mpt_device_driver_deregister);
8466EXPORT_SYMBOL(mpt_get_msg_frame);
8467EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05308468EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008469EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008470EXPORT_SYMBOL(mpt_send_handshake_request);
8471EXPORT_SYMBOL(mpt_verify_adapter);
8472EXPORT_SYMBOL(mpt_GetIocState);
8473EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008474EXPORT_SYMBOL(mpt_HardResetHandler);
8475EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008476EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008477EXPORT_SYMBOL(mpt_alloc_fw_memory);
8478EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02008479EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07008480EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008481
Linus Torvalds1da177e2005-04-16 15:20:36 -07008482/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008483/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008484 * fusion_init - Fusion MPT base driver initialization routine.
8485 *
8486 * Returns 0 for success, non-zero for failure.
8487 */
8488static int __init
8489fusion_init(void)
8490{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308491 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008492
8493 show_mptmod_ver(my_NAME, my_VERSION);
8494 printk(KERN_INFO COPYRIGHT "\n");
8495
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308496 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
8497 MptCallbacks[cb_idx] = NULL;
8498 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
8499 MptEvHandlers[cb_idx] = NULL;
8500 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008501 }
8502
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008503 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07008504 * EventNotification handling.
8505 */
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308506 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER,
8507 "mptbase_reply");
Linus Torvalds1da177e2005-04-16 15:20:36 -07008508
8509 /* Register for hard reset handling callbacks.
8510 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05308511 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008512
8513#ifdef CONFIG_PROC_FS
8514 (void) procmpt_create();
8515#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008516 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008517}
8518
8519/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008520/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008521 * fusion_exit - Perform driver unload cleanup.
8522 *
8523 * This routine frees all resources associated with each MPT adapter
8524 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
8525 */
8526static void __exit
8527fusion_exit(void)
8528{
8529
Linus Torvalds1da177e2005-04-16 15:20:36 -07008530 mpt_reset_deregister(mpt_base_index);
8531
8532#ifdef CONFIG_PROC_FS
8533 procmpt_destroy();
8534#endif
8535}
8536
Linus Torvalds1da177e2005-04-16 15:20:36 -07008537module_init(fusion_init);
8538module_exit(fusion_exit);