blob: 5d0ba4f5924ca5bf34547dabcab8cda8cbf2ff4a [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>
53#include <linux/slab.h>
54#include <linux/types.h>
55#include <linux/pci.h>
56#include <linux/kdev_t.h>
57#include <linux/blkdev.h>
58#include <linux/delay.h>
59#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040060#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <asm/io.h>
62#ifdef CONFIG_MTRR
63#include <asm/mtrr.h>
64#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#include "mptbase.h"
Eric Moore7c431e52007-06-13 16:34:36 -060067#include "lsi/mpi_log_fc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT base driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptbase"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/*
80 * cmd line parameters
81 */
Kashyap, Desaie3829682009-01-08 14:27:16 +053082
83static int mpt_msi_enable_spi;
84module_param(mpt_msi_enable_spi, int, 0);
85MODULE_PARM_DESC(mpt_msi_enable_spi, " Enable MSI Support for SPI \
86 controllers (default=0)");
87
88static int mpt_msi_enable_fc;
89module_param(mpt_msi_enable_fc, int, 0);
90MODULE_PARM_DESC(mpt_msi_enable_fc, " Enable MSI Support for FC \
91 controllers (default=0)");
92
93static int mpt_msi_enable_sas;
Yinghai Lu5ce78682009-02-18 11:25:32 -080094module_param(mpt_msi_enable_sas, int, 0);
Kashyap, Desaie3829682009-01-08 14:27:16 +053095MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS \
Yinghai Lu5ce78682009-02-18 11:25:32 -080096 controllers (default=0)");
Kashyap, Desaie3829682009-01-08 14:27:16 +053097
Christoph Hellwig4ddce142006-01-17 13:44:29 +000098
Eric Moore793955f2007-01-29 09:42:20 -070099static int mpt_channel_mapping;
100module_param(mpt_channel_mapping, int, 0);
101MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
102
Prakash, Sathya436ace72007-07-24 15:42:08 +0530103static int mpt_debug_level;
James Bottomleydb47c2d2007-07-28 13:40:21 -0400104static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
105module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
106 &mpt_debug_level, 0600);
Kashyap, Desaie3829682009-01-08 14:27:16 +0530107MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h \
108 - (default=0)");
109
Kashyap, Desai2f4c7822009-01-06 15:03:37 +0530110int mpt_fwfault_debug;
111EXPORT_SYMBOL(mpt_fwfault_debug);
112module_param_call(mpt_fwfault_debug, param_set_int, param_get_int,
113 &mpt_fwfault_debug, 0600);
114MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault"
115 " and halt Firmware on fault - (default=0)");
116
117
Prakash, Sathya436ace72007-07-24 15:42:08 +0530118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119#ifdef MFCNT
120static int mfcounter = 0;
121#define PRINT_MF_COUNT 20000
122#endif
123
124/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
125/*
126 * Public data...
127 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
Adrian Bunk15424922008-04-22 00:31:51 +0300129static struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
131#define WHOINIT_UNKNOWN 0xAA
132
133/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
134/*
135 * Private data...
136 */
137 /* Adapter link list */
138LIST_HEAD(ioc_list);
139 /* Callback lookup table */
140static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
141 /* Protocol driver class lookup table */
142static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
143 /* Event handler lookup table */
144static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
145 /* Reset handler lookup table */
146static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
147static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
148
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530150/*
151 * Driver Callback Index's
152 */
153static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
154static u8 last_drv_idx;
155
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
157/*
158 * Forward protos...
159 */
David Howells7d12e782006-10-05 14:55:46 +0100160static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530161static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
162 MPT_FRAME_HDR *reply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
164 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
165 int sleepFlag);
166static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
167static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
168static void mpt_adapter_disable(MPT_ADAPTER *ioc);
169static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
170
171static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
172static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
174static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
175static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
176static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
177static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200178static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
180static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
181static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
182static int PrimeIocFifos(MPT_ADAPTER *ioc);
183static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
184static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
185static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
186static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200188int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
190static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
191static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
192static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530193static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Kashyap, Desaifd761752009-05-29 16:39:06 +0530194static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch,
195 int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200197static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
198static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
200#ifdef CONFIG_PROC_FS
201static int procmpt_summary_read(char *buf, char **start, off_t offset,
202 int request, int *eof, void *data);
203static int procmpt_version_read(char *buf, char **start, off_t offset,
204 int request, int *eof, void *data);
205static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
206 int request, int *eof, void *data);
207#endif
208static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
209
Kashyap, Desaifd761752009-05-29 16:39:06 +0530210static int ProcessEventNotification(MPT_ADAPTER *ioc,
211 EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700212static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700214static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600215static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700216static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700217static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
219/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220static int __init fusion_init (void);
221static void __exit fusion_exit (void);
222
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223#define CHIPREG_READ32(addr) readl_relaxed(addr)
224#define CHIPREG_READ32_dmasync(addr) readl(addr)
225#define CHIPREG_WRITE32(addr,val) writel(val, addr)
226#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
227#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
228
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600229static void
230pci_disable_io_access(struct pci_dev *pdev)
231{
232 u16 command_reg;
233
234 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
235 command_reg &= ~1;
236 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
237}
238
239static void
240pci_enable_io_access(struct pci_dev *pdev)
241{
242 u16 command_reg;
243
244 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
245 command_reg |= 1;
246 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
247}
248
James Bottomleydb47c2d2007-07-28 13:40:21 -0400249static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
250{
251 int ret = param_set_int(val, kp);
252 MPT_ADAPTER *ioc;
253
254 if (ret)
255 return ret;
256
257 list_for_each_entry(ioc, &ioc_list, list)
258 ioc->debug_level = mpt_debug_level;
259 return 0;
260}
261
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530262/**
263 * mpt_get_cb_idx - obtain cb_idx for registered driver
264 * @dclass: class driver enum
265 *
266 * Returns cb_idx, or zero means it wasn't found
267 **/
268static u8
269mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
270{
271 u8 cb_idx;
272
273 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
274 if (MptDriverClass[cb_idx] == dclass)
275 return cb_idx;
276 return 0;
277}
278
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530279/**
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530280 * mpt_is_discovery_complete - determine if discovery has completed
281 * @ioc: per adatper instance
282 *
283 * Returns 1 when discovery completed, else zero.
284 */
285static int
286mpt_is_discovery_complete(MPT_ADAPTER *ioc)
287{
288 ConfigExtendedPageHeader_t hdr;
289 CONFIGPARMS cfg;
290 SasIOUnitPage0_t *buffer;
291 dma_addr_t dma_handle;
292 int rc = 0;
293
294 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
295 memset(&cfg, 0, sizeof(CONFIGPARMS));
296 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
297 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
298 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
299 cfg.cfghdr.ehdr = &hdr;
300 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
301
302 if ((mpt_config(ioc, &cfg)))
303 goto out;
304 if (!hdr.ExtPageLength)
305 goto out;
306
307 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
308 &dma_handle);
309 if (!buffer)
310 goto out;
311
312 cfg.physAddr = dma_handle;
313 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
314
315 if ((mpt_config(ioc, &cfg)))
316 goto out_free_consistent;
317
318 if (!(buffer->PhyData[0].PortFlags &
319 MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS))
320 rc = 1;
321
322 out_free_consistent:
323 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
324 buffer, dma_handle);
325 out:
326 return rc;
327}
328
329/**
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530330 * mpt_fault_reset_work - work performed on workq after ioc fault
331 * @work: input argument, used to derive ioc
332 *
333**/
334static void
335mpt_fault_reset_work(struct work_struct *work)
336{
337 MPT_ADAPTER *ioc =
338 container_of(work, MPT_ADAPTER, fault_reset_work.work);
339 u32 ioc_raw_state;
340 int rc;
341 unsigned long flags;
342
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530343 if (ioc->ioc_reset_in_progress || !ioc->active)
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530344 goto out;
345
346 ioc_raw_state = mpt_GetIocState(ioc, 0);
347 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
348 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700349 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530350 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700351 ioc->name, __func__);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530352 rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
353 printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700354 __func__, (rc == 0) ? "success" : "failed");
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530355 ioc_raw_state = mpt_GetIocState(ioc, 0);
356 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
357 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
358 "reset (%04xh)\n", ioc->name, ioc_raw_state &
359 MPI_DOORBELL_DATA_MASK);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530360 } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) {
361 if ((mpt_is_discovery_complete(ioc))) {
362 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing "
363 "discovery_quiesce_io flag\n", ioc->name));
364 ioc->sas_discovery_quiesce_io = 0;
365 }
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530366 }
367
368 out:
369 /*
370 * Take turns polling alternate controller
371 */
372 if (ioc->alt_ioc)
373 ioc = ioc->alt_ioc;
374
375 /* rearm the timer */
Kashyap, Desai2f187862009-05-29 16:52:37 +0530376 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530377 if (ioc->reset_work_q)
378 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
379 msecs_to_jiffies(MPT_POLLING_INTERVAL));
Kashyap, Desai2f187862009-05-29 16:52:37 +0530380 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530381}
382
383
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600384/*
385 * Process turbo (context) reply...
386 */
387static void
388mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
389{
390 MPT_FRAME_HDR *mf = NULL;
391 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530392 u16 req_idx = 0;
393 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600394
Prakash, Sathya436ace72007-07-24 15:42:08 +0530395 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600396 ioc->name, pa));
397
398 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
399 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
400 req_idx = pa & 0x0000FFFF;
401 cb_idx = (pa & 0x00FF0000) >> 16;
402 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
403 break;
404 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530405 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600406 /*
407 * Blind set of mf to NULL here was fatal
408 * after lan_reply says "freeme"
409 * Fix sort of combined with an optimization here;
410 * added explicit check for case where lan_reply
411 * was just returning 1 and doing nothing else.
412 * For this case skip the callback, but set up
413 * proper mf value first here:-)
414 */
415 if ((pa & 0x58000000) == 0x58000000) {
416 req_idx = pa & 0x0000FFFF;
417 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
418 mpt_free_msg_frame(ioc, mf);
419 mb();
420 return;
421 break;
422 }
423 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
424 break;
425 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530426 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600427 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
428 break;
429 default:
430 cb_idx = 0;
431 BUG();
432 }
433
434 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530435 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600436 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600437 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700438 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600439 goto out;
440 }
441
442 if (MptCallbacks[cb_idx](ioc, mf, mr))
443 mpt_free_msg_frame(ioc, mf);
444 out:
445 mb();
446}
447
448static void
449mpt_reply(MPT_ADAPTER *ioc, u32 pa)
450{
451 MPT_FRAME_HDR *mf;
452 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530453 u16 req_idx;
454 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600455 int freeme;
456
457 u32 reply_dma_low;
458 u16 ioc_stat;
459
460 /* non-TURBO reply! Hmmm, something may be up...
461 * Newest turbo reply mechanism; get address
462 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
463 */
464
465 /* Map DMA address of reply header to cpu address.
466 * pa is 32 bits - but the dma address may be 32 or 64 bits
467 * get offset based only only the low addresses
468 */
469
470 reply_dma_low = (pa <<= 1);
471 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
472 (reply_dma_low - ioc->reply_frames_low_dma));
473
474 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
475 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
476 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
477
Prakash, Sathya436ace72007-07-24 15:42:08 +0530478 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 -0600479 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600480 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600481
482 /* Check/log IOC log info
483 */
484 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
485 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
486 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
487 if (ioc->bus_type == FC)
488 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700489 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700490 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600491 else if (ioc->bus_type == SAS)
492 mpt_sas_log_info(ioc, log_info);
493 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600494
Eric Moorec6c727a2007-01-29 09:44:54 -0700495 if (ioc_stat & MPI_IOCSTATUS_MASK)
496 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600497
498 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530499 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600500 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600501 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700502 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600503 freeme = 0;
504 goto out;
505 }
506
507 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
508
509 out:
510 /* Flush (non-TURBO) reply with a WRITE! */
511 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
512
513 if (freeme)
514 mpt_free_msg_frame(ioc, mf);
515 mb();
516}
517
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800519/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
521 * @irq: irq number (not used)
522 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 *
524 * This routine is registered via the request_irq() kernel API call,
525 * and handles all interrupts generated from a specific MPT adapter
526 * (also referred to as a IO Controller or IOC).
527 * This routine must clear the interrupt from the adapter and does
528 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200529 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 *
531 * This routine handles register-level access of the adapter but
532 * dispatches (calls) a protocol-specific callback routine to handle
533 * the protocol-specific details of the MPT request completion.
534 */
535static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100536mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600538 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600539 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
540
541 if (pa == 0xFFFFFFFF)
542 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
544 /*
545 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600547 do {
548 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600549 mpt_reply(ioc, pa);
550 else
551 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600552 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
553 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
555 return IRQ_HANDLED;
556}
557
558/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800559/**
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530560 * mptbase_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 * @ioc: Pointer to MPT_ADAPTER structure
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530562 * @req: Pointer to original MPT request frame
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
564 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800565 * MPT base driver's callback routine; all base driver
566 * "internal" request/reply processing is routed here.
567 * Currently used for EventNotification and EventAck handling.
568 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200569 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 * should be freed, or 0 if it shouldn't.
571 */
572static int
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530573mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530575 EventNotificationReply_t *pEventReply;
576 u8 event;
577 int evHandlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 int freereq = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530580 switch (reply->u.hdr.Function) {
581 case MPI_FUNCTION_EVENT_NOTIFICATION:
582 pEventReply = (EventNotificationReply_t *)reply;
583 evHandlers = 0;
584 ProcessEventNotification(ioc, pEventReply, &evHandlers);
585 event = le32_to_cpu(pEventReply->Event) & 0xFF;
586 if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 freereq = 0;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530588 if (event != MPI_EVENT_EVENT_CHANGE)
589 break;
590 case MPI_FUNCTION_CONFIG:
591 case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
592 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
593 if (reply) {
594 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
595 memcpy(ioc->mptbase_cmds.reply, reply,
596 min(MPT_DEFAULT_FRAME_SIZE,
597 4 * reply->u.reply.MsgLength));
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200598 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530599 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
600 ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
601 complete(&ioc->mptbase_cmds.done);
602 } else
603 freereq = 0;
604 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF)
605 freereq = 1;
606 break;
607 case MPI_FUNCTION_EVENT_ACK:
608 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
609 "EventAck reply received\n", ioc->name));
610 break;
611 default:
612 printk(MYIOC_s_ERR_FMT
613 "Unexpected msg function (=%02Xh) reply received!\n",
614 ioc->name, reply->u.hdr.Function);
615 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 }
617
618 /*
619 * Conditionally tell caller to free the original
620 * EventNotification/EventAck/unexpected request frame!
621 */
622 return freereq;
623}
624
625/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
626/**
627 * mpt_register - Register protocol-specific main callback handler.
628 * @cbfunc: callback function pointer
629 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
630 *
631 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800632 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 * protocol-specific driver must do this before it will be able to
634 * use any IOC resources, such as obtaining request frames.
635 *
636 * NOTES: The SCSI protocol driver currently calls this routine thrice
637 * in order to register separate callbacks; one for "normal" SCSI IO;
638 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
639 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530640 * Returns u8 valued "handle" in the range (and S.O.D. order)
641 * {N,...,7,6,5,...,1} if successful.
642 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
643 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530645u8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
647{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530648 u8 cb_idx;
649 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
651 /*
652 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
653 * (slot/handle 0 is reserved!)
654 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530655 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
656 if (MptCallbacks[cb_idx] == NULL) {
657 MptCallbacks[cb_idx] = cbfunc;
658 MptDriverClass[cb_idx] = dclass;
659 MptEvHandlers[cb_idx] = NULL;
660 last_drv_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 break;
662 }
663 }
664
665 return last_drv_idx;
666}
667
668/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
669/**
670 * mpt_deregister - Deregister a protocol drivers resources.
671 * @cb_idx: previously registered callback handle
672 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800673 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 * module is unloaded.
675 */
676void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530677mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600679 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 MptCallbacks[cb_idx] = NULL;
681 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
682 MptEvHandlers[cb_idx] = NULL;
683
684 last_drv_idx++;
685 }
686}
687
688/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
689/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800690 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 * @cb_idx: previously registered (via mpt_register) callback handle
692 * @ev_cbfunc: callback function
693 *
694 * This routine can be called by one or more protocol-specific drivers
695 * if/when they choose to be notified of MPT events.
696 *
697 * Returns 0 for success.
698 */
699int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530700mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600702 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 return -1;
704
705 MptEvHandlers[cb_idx] = ev_cbfunc;
706 return 0;
707}
708
709/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
710/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800711 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 * @cb_idx: previously registered callback handle
713 *
714 * Each protocol-specific driver should call this routine
715 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800716 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 */
718void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530719mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600721 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 return;
723
724 MptEvHandlers[cb_idx] = NULL;
725}
726
727/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
728/**
729 * mpt_reset_register - Register protocol-specific IOC reset handler.
730 * @cb_idx: previously registered (via mpt_register) callback handle
731 * @reset_func: reset function
732 *
733 * This routine can be called by one or more protocol-specific drivers
734 * if/when they choose to be notified of IOC resets.
735 *
736 * Returns 0 for success.
737 */
738int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530739mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530741 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 return -1;
743
744 MptResetHandlers[cb_idx] = reset_func;
745 return 0;
746}
747
748/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
749/**
750 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
751 * @cb_idx: previously registered callback handle
752 *
753 * Each protocol-specific driver should call this routine
754 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800755 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 */
757void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530758mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530760 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 return;
762
763 MptResetHandlers[cb_idx] = NULL;
764}
765
766/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
767/**
768 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800769 * @dd_cbfunc: driver callbacks struct
770 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 */
772int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530773mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774{
775 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600776 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777
Eric Moore8d6d83e2007-09-14 18:47:40 -0600778 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400779 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
781 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
782
783 /* call per pci device probe entry point */
784 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600785 id = ioc->pcidev->driver ?
786 ioc->pcidev->driver->id_table : NULL;
787 if (dd_cbfunc->probe)
788 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 }
790
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400791 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792}
793
794/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
795/**
796 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800797 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 */
799void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530800mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801{
802 struct mpt_pci_driver *dd_cbfunc;
803 MPT_ADAPTER *ioc;
804
Eric Moore8d6d83e2007-09-14 18:47:40 -0600805 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 return;
807
808 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
809
810 list_for_each_entry(ioc, &ioc_list, list) {
811 if (dd_cbfunc->remove)
812 dd_cbfunc->remove(ioc->pcidev);
813 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200814
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 MptDeviceDriverHandlers[cb_idx] = NULL;
816}
817
818
819/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
820/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800821 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530822 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 * @ioc: Pointer to MPT adapter structure
824 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800825 * Obtain an MPT request frame from the pool (of 1024) that are
826 * allocated per MPT adapter.
827 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 * Returns pointer to a MPT request frame or %NULL if none are available
829 * or IOC is not active.
830 */
831MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530832mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833{
834 MPT_FRAME_HDR *mf;
835 unsigned long flags;
836 u16 req_idx; /* Request index */
837
838 /* validate handle and ioc identifier */
839
840#ifdef MFCNT
841 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600842 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
843 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844#endif
845
846 /* If interrupts are not attached, do not return a request frame */
847 if (!ioc->active)
848 return NULL;
849
850 spin_lock_irqsave(&ioc->FreeQlock, flags);
851 if (!list_empty(&ioc->FreeQ)) {
852 int req_offset;
853
854 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
855 u.frame.linkage.list);
856 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200857 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530858 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
860 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500861 req_idx = req_offset / ioc->req_sz;
862 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600864 /* Default, will be changed if necessary in SG generation */
865 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866#ifdef MFCNT
867 ioc->mfcnt++;
868#endif
869 }
870 else
871 mf = NULL;
872 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
873
874#ifdef MFCNT
875 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600876 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
877 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
878 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 mfcounter++;
880 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600881 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
882 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883#endif
884
Eric Moore29dd3602007-09-14 18:46:51 -0600885 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
886 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 return mf;
888}
889
890/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
891/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800892 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530893 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 * @ioc: Pointer to MPT adapter structure
895 * @mf: Pointer to MPT request frame
896 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800897 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 * specific MPT adapter.
899 */
900void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530901mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902{
903 u32 mf_dma_addr;
904 int req_offset;
905 u16 req_idx; /* Request index */
906
907 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530908 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
910 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500911 req_idx = req_offset / ioc->req_sz;
912 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
914
Prakash, Sathya436ace72007-07-24 15:42:08 +0530915 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200917 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600918 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
919 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
920 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
922}
923
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530924/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800925 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530926 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530927 * @ioc: Pointer to MPT adapter structure
928 * @mf: Pointer to MPT request frame
929 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800930 * Send a protocol-specific MPT request frame to an IOC using
931 * hi-priority request queue.
932 *
933 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530934 * specific MPT adapter.
935 **/
936void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530937mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530938{
939 u32 mf_dma_addr;
940 int req_offset;
941 u16 req_idx; /* Request index */
942
943 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530944 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530945 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
946 req_idx = req_offset / ioc->req_sz;
947 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
948 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
949
950 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
951
952 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
953 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
954 ioc->name, mf_dma_addr, req_idx));
955 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
956}
957
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
959/**
960 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 * @ioc: Pointer to MPT adapter structure
962 * @mf: Pointer to MPT request frame
963 *
964 * This routine places a MPT request frame back on the MPT adapter's
965 * FreeQ.
966 */
967void
968mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
969{
970 unsigned long flags;
971
972 /* Put Request back on FreeQ! */
973 spin_lock_irqsave(&ioc->FreeQlock, flags);
Kashyap, Desai2f187862009-05-29 16:52:37 +0530974 if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf)
975 goto out;
976 /* signature to know if this mf is freed */
977 mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
979#ifdef MFCNT
980 ioc->mfcnt--;
981#endif
Kashyap, Desai2f187862009-05-29 16:52:37 +0530982 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
984}
985
986/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
987/**
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530988 * mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 * @pAddr: virtual address for SGE
990 * @flagslength: SGE flags and data transfer length
991 * @dma_addr: Physical address
992 *
993 * This routine places a MPT request frame back on the MPT adapter's
994 * FreeQ.
995 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530996static void
997mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998{
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530999 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
1000 pSge->FlagsLength = cpu_to_le32(flagslength);
1001 pSge->Address = cpu_to_le32(dma_addr);
1002}
1003
1004/**
1005 * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
1006 * @pAddr: virtual address for SGE
1007 * @flagslength: SGE flags and data transfer length
1008 * @dma_addr: Physical address
1009 *
1010 * This routine places a MPT request frame back on the MPT adapter's
1011 * FreeQ.
1012 **/
1013static void
1014mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1015{
1016 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1017 pSge->Address.Low = cpu_to_le32
1018 (lower_32_bits((unsigned long)(dma_addr)));
1019 pSge->Address.High = cpu_to_le32
1020 (upper_32_bits((unsigned long)dma_addr));
1021 pSge->FlagsLength = cpu_to_le32
1022 ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1023}
1024
1025/**
Randy Dunlap9cf46a32009-06-13 19:37:18 -07001026 * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr (1078 workaround).
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301027 * @pAddr: virtual address for SGE
1028 * @flagslength: SGE flags and data transfer length
1029 * @dma_addr: Physical address
1030 *
1031 * This routine places a MPT request frame back on the MPT adapter's
1032 * FreeQ.
1033 **/
1034static void
1035mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1036{
1037 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1038 u32 tmp;
1039
1040 pSge->Address.Low = cpu_to_le32
1041 (lower_32_bits((unsigned long)(dma_addr)));
1042 tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
1043
1044 /*
1045 * 1078 errata workaround for the 36GB limitation
1046 */
1047 if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {
1048 flagslength |=
1049 MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
1050 tmp |= (1<<31);
1051 if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
1052 printk(KERN_DEBUG "1078 P0M2 addressing for "
1053 "addr = 0x%llx len = %d\n",
1054 (unsigned long long)dma_addr,
1055 MPI_SGE_LENGTH(flagslength));
1056 }
1057
1058 pSge->Address.High = cpu_to_le32(tmp);
1059 pSge->FlagsLength = cpu_to_le32(
1060 (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1061}
1062
1063/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1064/**
1065 * mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
1066 * @pAddr: virtual address for SGE
1067 * @next: nextChainOffset value (u32's)
1068 * @length: length of next SGL segment
1069 * @dma_addr: Physical address
1070 *
1071 */
1072static void
1073mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1074{
1075 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
1076 pChain->Length = cpu_to_le16(length);
1077 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
1078 pChain->NextChainOffset = next;
1079 pChain->Address = cpu_to_le32(dma_addr);
1080}
1081
1082/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1083/**
1084 * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
1085 * @pAddr: virtual address for SGE
1086 * @next: nextChainOffset value (u32's)
1087 * @length: length of next SGL segment
1088 * @dma_addr: Physical address
1089 *
1090 */
1091static void
1092mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1093{
1094 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 u32 tmp = dma_addr & 0xFFFFFFFF;
1096
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301097 pChain->Length = cpu_to_le16(length);
1098 pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
1099 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301101 pChain->NextChainOffset = next;
1102
1103 pChain->Address.Low = cpu_to_le32(tmp);
1104 tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
1105 pChain->Address.High = cpu_to_le32(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106}
1107
1108/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1109/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001110 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301111 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 * @ioc: Pointer to MPT adapter structure
1113 * @reqBytes: Size of the request in bytes
1114 * @req: Pointer to MPT request frame
1115 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1116 *
1117 * This routine is used exclusively to send MptScsiTaskMgmt
1118 * requests since they are required to be sent via doorbell handshake.
1119 *
1120 * NOTE: It is the callers responsibility to byte-swap fields in the
1121 * request which are greater than 1 byte in size.
1122 *
1123 * Returns 0 for success, non-zero for failure.
1124 */
1125int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301126mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127{
Eric Moorecd2c6192007-01-29 09:47:47 -07001128 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 u8 *req_as_bytes;
1130 int ii;
1131
1132 /* State is known to be good upon entering
1133 * this function so issue the bus reset
1134 * request.
1135 */
1136
1137 /*
1138 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1139 * setting cb_idx/req_idx. But ONLY if this request
1140 * is in proper (pre-alloc'd) request buffer range...
1141 */
1142 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1143 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1144 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1145 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301146 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 }
1148
1149 /* Make sure there are no doorbells */
1150 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001151
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1153 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1154 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1155
1156 /* Wait for IOC doorbell int */
1157 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1158 return ii;
1159 }
1160
1161 /* Read doorbell and check for active bit */
1162 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1163 return -5;
1164
Eric Moore29dd3602007-09-14 18:46:51 -06001165 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001166 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167
1168 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1169
1170 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1171 return -2;
1172 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001173
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 /* Send request via doorbell handshake */
1175 req_as_bytes = (u8 *) req;
1176 for (ii = 0; ii < reqBytes/4; ii++) {
1177 u32 word;
1178
1179 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1180 (req_as_bytes[(ii*4) + 1] << 8) |
1181 (req_as_bytes[(ii*4) + 2] << 16) |
1182 (req_as_bytes[(ii*4) + 3] << 24));
1183 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1184 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1185 r = -3;
1186 break;
1187 }
1188 }
1189
1190 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1191 r = 0;
1192 else
1193 r = -4;
1194
1195 /* Make sure there are no doorbells */
1196 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001197
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 return r;
1199}
1200
1201/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1202/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001203 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001204 * @ioc: Pointer to MPT adapter structure
1205 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001206 * @sleepFlag: Specifies whether the process can sleep
1207 *
1208 * Provides mechanism for the host driver to control the IOC's
1209 * Host Page Buffer access.
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001210 *
1211 * Access Control Value - bits[15:12]
1212 * 0h Reserved
1213 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1214 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1215 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1216 *
1217 * Returns 0 for success, non-zero for failure.
1218 */
1219
1220static int
1221mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1222{
1223 int r = 0;
1224
1225 /* return if in use */
1226 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1227 & MPI_DOORBELL_ACTIVE)
1228 return -1;
1229
1230 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1231
1232 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1233 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1234 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1235 (access_control_value<<12)));
1236
1237 /* Wait for IOC to clear Doorbell Status bit */
1238 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1239 return -2;
1240 }else
1241 return 0;
1242}
1243
1244/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1245/**
1246 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001247 * @ioc: Pointer to pointer to IOC adapter
1248 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001249 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001250 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001251 * Returns 0 for success, non-zero for failure.
1252 */
1253static int
1254mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1255{
1256 char *psge;
1257 int flags_length;
1258 u32 host_page_buffer_sz=0;
1259
1260 if(!ioc->HostPageBuffer) {
1261
1262 host_page_buffer_sz =
1263 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1264
1265 if(!host_page_buffer_sz)
1266 return 0; /* fw doesn't need any host buffers */
1267
1268 /* spin till we get enough memory */
1269 while(host_page_buffer_sz > 0) {
1270
1271 if((ioc->HostPageBuffer = pci_alloc_consistent(
1272 ioc->pcidev,
1273 host_page_buffer_sz,
1274 &ioc->HostPageBuffer_dma)) != NULL) {
1275
Prakash, Sathya436ace72007-07-24 15:42:08 +05301276 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001277 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001278 ioc->name, ioc->HostPageBuffer,
1279 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001280 host_page_buffer_sz));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001281 ioc->alloc_total += host_page_buffer_sz;
1282 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1283 break;
1284 }
1285
1286 host_page_buffer_sz -= (4*1024);
1287 }
1288 }
1289
1290 if(!ioc->HostPageBuffer) {
1291 printk(MYIOC_s_ERR_FMT
1292 "Failed to alloc memory for host_page_buffer!\n",
1293 ioc->name);
1294 return -999;
1295 }
1296
1297 psge = (char *)&ioc_init->HostPageBufferSGE;
1298 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1299 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1300 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1301 MPI_SGE_FLAGS_HOST_TO_IOC |
1302 MPI_SGE_FLAGS_END_OF_BUFFER;
1303 if (sizeof(dma_addr_t) == sizeof(u64)) {
1304 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1305 }
1306 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1307 flags_length |= ioc->HostPageBuffer_sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301308 ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001309 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1310
1311return 0;
1312}
1313
1314/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1315/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001316 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 * @iocid: IOC unique identifier (integer)
1318 * @iocpp: Pointer to pointer to IOC adapter
1319 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001320 * Given a unique IOC identifier, set pointer to the associated MPT
1321 * adapter structure.
1322 *
1323 * Returns iocid and sets iocpp if iocid is found.
1324 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 */
1326int
1327mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1328{
1329 MPT_ADAPTER *ioc;
1330
1331 list_for_each_entry(ioc,&ioc_list,list) {
1332 if (ioc->id == iocid) {
1333 *iocpp =ioc;
1334 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001337
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 *iocpp = NULL;
1339 return -1;
1340}
1341
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301342/**
1343 * mpt_get_product_name - returns product string
1344 * @vendor: pci vendor id
1345 * @device: pci device id
1346 * @revision: pci revision id
1347 * @prod_name: string returned
1348 *
1349 * Returns product string displayed when driver loads,
1350 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1351 *
1352 **/
1353static void
1354mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1355{
1356 char *product_str = NULL;
1357
1358 if (vendor == PCI_VENDOR_ID_BROCADE) {
1359 switch (device)
1360 {
1361 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1362 switch (revision)
1363 {
1364 case 0x00:
1365 product_str = "BRE040 A0";
1366 break;
1367 case 0x01:
1368 product_str = "BRE040 A1";
1369 break;
1370 default:
1371 product_str = "BRE040";
1372 break;
1373 }
1374 break;
1375 }
1376 goto out;
1377 }
1378
1379 switch (device)
1380 {
1381 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1382 product_str = "LSIFC909 B1";
1383 break;
1384 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1385 product_str = "LSIFC919 B0";
1386 break;
1387 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1388 product_str = "LSIFC929 B0";
1389 break;
1390 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1391 if (revision < 0x80)
1392 product_str = "LSIFC919X A0";
1393 else
1394 product_str = "LSIFC919XL A1";
1395 break;
1396 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1397 if (revision < 0x80)
1398 product_str = "LSIFC929X A0";
1399 else
1400 product_str = "LSIFC929XL A1";
1401 break;
1402 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1403 product_str = "LSIFC939X A1";
1404 break;
1405 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1406 product_str = "LSIFC949X A1";
1407 break;
1408 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1409 switch (revision)
1410 {
1411 case 0x00:
1412 product_str = "LSIFC949E A0";
1413 break;
1414 case 0x01:
1415 product_str = "LSIFC949E A1";
1416 break;
1417 default:
1418 product_str = "LSIFC949E";
1419 break;
1420 }
1421 break;
1422 case MPI_MANUFACTPAGE_DEVID_53C1030:
1423 switch (revision)
1424 {
1425 case 0x00:
1426 product_str = "LSI53C1030 A0";
1427 break;
1428 case 0x01:
1429 product_str = "LSI53C1030 B0";
1430 break;
1431 case 0x03:
1432 product_str = "LSI53C1030 B1";
1433 break;
1434 case 0x07:
1435 product_str = "LSI53C1030 B2";
1436 break;
1437 case 0x08:
1438 product_str = "LSI53C1030 C0";
1439 break;
1440 case 0x80:
1441 product_str = "LSI53C1030T A0";
1442 break;
1443 case 0x83:
1444 product_str = "LSI53C1030T A2";
1445 break;
1446 case 0x87:
1447 product_str = "LSI53C1030T A3";
1448 break;
1449 case 0xc1:
1450 product_str = "LSI53C1020A A1";
1451 break;
1452 default:
1453 product_str = "LSI53C1030";
1454 break;
1455 }
1456 break;
1457 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1458 switch (revision)
1459 {
1460 case 0x03:
1461 product_str = "LSI53C1035 A2";
1462 break;
1463 case 0x04:
1464 product_str = "LSI53C1035 B0";
1465 break;
1466 default:
1467 product_str = "LSI53C1035";
1468 break;
1469 }
1470 break;
1471 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1472 switch (revision)
1473 {
1474 case 0x00:
1475 product_str = "LSISAS1064 A1";
1476 break;
1477 case 0x01:
1478 product_str = "LSISAS1064 A2";
1479 break;
1480 case 0x02:
1481 product_str = "LSISAS1064 A3";
1482 break;
1483 case 0x03:
1484 product_str = "LSISAS1064 A4";
1485 break;
1486 default:
1487 product_str = "LSISAS1064";
1488 break;
1489 }
1490 break;
1491 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1492 switch (revision)
1493 {
1494 case 0x00:
1495 product_str = "LSISAS1064E A0";
1496 break;
1497 case 0x01:
1498 product_str = "LSISAS1064E B0";
1499 break;
1500 case 0x02:
1501 product_str = "LSISAS1064E B1";
1502 break;
1503 case 0x04:
1504 product_str = "LSISAS1064E B2";
1505 break;
1506 case 0x08:
1507 product_str = "LSISAS1064E B3";
1508 break;
1509 default:
1510 product_str = "LSISAS1064E";
1511 break;
1512 }
1513 break;
1514 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1515 switch (revision)
1516 {
1517 case 0x00:
1518 product_str = "LSISAS1068 A0";
1519 break;
1520 case 0x01:
1521 product_str = "LSISAS1068 B0";
1522 break;
1523 case 0x02:
1524 product_str = "LSISAS1068 B1";
1525 break;
1526 default:
1527 product_str = "LSISAS1068";
1528 break;
1529 }
1530 break;
1531 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1532 switch (revision)
1533 {
1534 case 0x00:
1535 product_str = "LSISAS1068E A0";
1536 break;
1537 case 0x01:
1538 product_str = "LSISAS1068E B0";
1539 break;
1540 case 0x02:
1541 product_str = "LSISAS1068E B1";
1542 break;
1543 case 0x04:
1544 product_str = "LSISAS1068E B2";
1545 break;
1546 case 0x08:
1547 product_str = "LSISAS1068E B3";
1548 break;
1549 default:
1550 product_str = "LSISAS1068E";
1551 break;
1552 }
1553 break;
1554 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1555 switch (revision)
1556 {
1557 case 0x00:
1558 product_str = "LSISAS1078 A0";
1559 break;
1560 case 0x01:
1561 product_str = "LSISAS1078 B0";
1562 break;
1563 case 0x02:
1564 product_str = "LSISAS1078 C0";
1565 break;
1566 case 0x03:
1567 product_str = "LSISAS1078 C1";
1568 break;
1569 case 0x04:
1570 product_str = "LSISAS1078 C2";
1571 break;
1572 default:
1573 product_str = "LSISAS1078";
1574 break;
1575 }
1576 break;
1577 }
1578
1579 out:
1580 if (product_str)
1581 sprintf(prod_name, "%s", product_str);
1582}
1583
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301584/**
1585 * mpt_mapresources - map in memory mapped io
1586 * @ioc: Pointer to pointer to IOC adapter
1587 *
1588 **/
1589static int
1590mpt_mapresources(MPT_ADAPTER *ioc)
1591{
1592 u8 __iomem *mem;
1593 int ii;
1594 unsigned long mem_phys;
1595 unsigned long port;
1596 u32 msize;
1597 u32 psize;
1598 u8 revision;
1599 int r = -ENODEV;
1600 struct pci_dev *pdev;
1601
1602 pdev = ioc->pcidev;
1603 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1604 if (pci_enable_device_mem(pdev)) {
1605 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1606 "failed\n", ioc->name);
1607 return r;
1608 }
1609 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1610 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1611 "MEM failed\n", ioc->name);
1612 return r;
1613 }
1614
1615 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1616
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301617 if (sizeof(dma_addr_t) > 4) {
1618 const uint64_t required_mask = dma_get_required_mask
1619 (&pdev->dev);
1620 if (required_mask > DMA_BIT_MASK(32)
1621 && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
1622 && !pci_set_consistent_dma_mask(pdev,
1623 DMA_BIT_MASK(64))) {
1624 ioc->dma_mask = DMA_BIT_MASK(64);
1625 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1626 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1627 ioc->name));
1628 } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1629 && !pci_set_consistent_dma_mask(pdev,
1630 DMA_BIT_MASK(32))) {
1631 ioc->dma_mask = DMA_BIT_MASK(32);
1632 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1633 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1634 ioc->name));
1635 } else {
1636 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1637 ioc->name, pci_name(pdev));
1638 return r;
1639 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301640 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301641 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1642 && !pci_set_consistent_dma_mask(pdev,
1643 DMA_BIT_MASK(32))) {
1644 ioc->dma_mask = DMA_BIT_MASK(32);
1645 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1646 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1647 ioc->name));
1648 } else {
1649 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1650 ioc->name, pci_name(pdev));
1651 return r;
1652 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301653 }
1654
1655 mem_phys = msize = 0;
1656 port = psize = 0;
1657 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1658 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1659 if (psize)
1660 continue;
1661 /* Get I/O space! */
1662 port = pci_resource_start(pdev, ii);
1663 psize = pci_resource_len(pdev, ii);
1664 } else {
1665 if (msize)
1666 continue;
1667 /* Get memmap */
1668 mem_phys = pci_resource_start(pdev, ii);
1669 msize = pci_resource_len(pdev, ii);
1670 }
1671 }
1672 ioc->mem_size = msize;
1673
1674 mem = NULL;
1675 /* Get logical ptr for PciMem0 space */
1676 /*mem = ioremap(mem_phys, msize);*/
1677 mem = ioremap(mem_phys, msize);
1678 if (mem == NULL) {
1679 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1680 " memory!\n", ioc->name);
1681 return -EINVAL;
1682 }
1683 ioc->memmap = mem;
1684 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n",
1685 ioc->name, mem, mem_phys));
1686
1687 ioc->mem_phys = mem_phys;
1688 ioc->chip = (SYSIF_REGS __iomem *)mem;
1689
1690 /* Save Port IO values in case we need to do downloadboot */
1691 ioc->pio_mem_phys = port;
1692 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1693
1694 return 0;
1695}
1696
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001698/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001699 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001701 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 *
1703 * This routine performs all the steps necessary to bring the IOC of
1704 * a MPT adapter to a OPERATIONAL state. This includes registering
1705 * memory regions, registering the interrupt, and allocating request
1706 * and reply memory pools.
1707 *
1708 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1709 * MPT adapter.
1710 *
1711 * Returns 0 for success, non-zero for failure.
1712 *
1713 * TODO: Add support for polled controllers
1714 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001715int
1716mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717{
1718 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301719 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 u8 revision;
1722 u8 pcixcmd;
1723 static int mpt_ids = 0;
1724#ifdef CONFIG_PROC_FS
1725 struct proc_dir_entry *dent, *ent;
1726#endif
1727
Jesper Juhl56876192007-08-10 14:50:51 -07001728 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1729 if (ioc == NULL) {
1730 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1731 return -ENOMEM;
1732 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301733
Eric Moore29dd3602007-09-14 18:46:51 -06001734 ioc->id = mpt_ids++;
1735 sprintf(ioc->name, "ioc%d", ioc->id);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301736 dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Jesper Juhl56876192007-08-10 14:50:51 -07001737
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301738 /*
1739 * set initial debug level
1740 * (refer to mptdebug.h)
1741 *
1742 */
1743 ioc->debug_level = mpt_debug_level;
1744 if (mpt_debug_level)
1745 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301746
Eric Moore29dd3602007-09-14 18:46:51 -06001747 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001748
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301749 ioc->pcidev = pdev;
1750 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001751 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 return r;
1753 }
1754
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301755 /*
1756 * Setting up proper handlers for scatter gather handling
1757 */
1758 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
1759 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
1760 ioc->add_sge = &mpt_add_sge_64bit_1078;
1761 else
1762 ioc->add_sge = &mpt_add_sge_64bit;
1763 ioc->add_chain = &mpt_add_chain_64bit;
1764 ioc->sg_addr_size = 8;
1765 } else {
1766 ioc->add_sge = &mpt_add_sge;
1767 ioc->add_chain = &mpt_add_chain;
1768 ioc->sg_addr_size = 4;
1769 }
1770 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
1771
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 ioc->alloc_total = sizeof(MPT_ADAPTER);
1773 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1774 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001775
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 ioc->pcidev = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301778 spin_lock_init(&ioc->taskmgmt_lock);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05301779 mutex_init(&ioc->internal_cmds.mutex);
1780 init_completion(&ioc->internal_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301781 mutex_init(&ioc->mptbase_cmds.mutex);
1782 init_completion(&ioc->mptbase_cmds.done);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301783 mutex_init(&ioc->taskmgmt_cmds.mutex);
1784 init_completion(&ioc->taskmgmt_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301785
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 /* Initialize the event logging.
1787 */
1788 ioc->eventTypes = 0; /* None */
1789 ioc->eventContext = 0;
1790 ioc->eventLogSize = 0;
1791 ioc->events = NULL;
1792
1793#ifdef MFCNT
1794 ioc->mfcnt = 0;
1795#endif
1796
Kashyap, Desai2f187862009-05-29 16:52:37 +05301797 ioc->sh = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 ioc->cached_fw = NULL;
1799
1800 /* Initilize SCSI Config Data structure
1801 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001802 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
Michael Reed05e8ec12006-01-13 14:31:54 -06001804 /* Initialize the fc rport list head.
1805 */
1806 INIT_LIST_HEAD(&ioc->fc_rports);
1807
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 /* Find lookup slot. */
1809 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001810
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301811
1812 /* Initialize workqueue */
1813 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301814
Kashyap, Desai2f187862009-05-29 16:52:37 +05301815 snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN,
Kay Sieversaab0de22008-05-02 06:02:41 +02001816 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301817 ioc->reset_work_q =
1818 create_singlethread_workqueue(ioc->reset_work_q_name);
1819 if (!ioc->reset_work_q) {
1820 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1821 ioc->name);
1822 pci_release_selected_regions(pdev, ioc->bars);
1823 kfree(ioc);
1824 return -ENOMEM;
1825 }
1826
Eric Moore29dd3602007-09-14 18:46:51 -06001827 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1828 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301830 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1831 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1832
1833 switch (pdev->device)
1834 {
1835 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1836 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1837 ioc->errata_flag_1064 = 1;
1838 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1839 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1840 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1841 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301843 break;
1844
1845 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 /* 929X Chip Fix. Set Split transactions level
1848 * for PCIX. Set MOST bits to zero.
1849 */
1850 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1851 pcixcmd &= 0x8F;
1852 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1853 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 /* 929XL Chip Fix. Set MMRBC to 0x08.
1855 */
1856 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1857 pcixcmd |= 0x08;
1858 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1859 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301861 break;
1862
1863 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 /* 919X Chip Fix. Set Split transactions level
1865 * for PCIX. Set MOST bits to zero.
1866 */
1867 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1868 pcixcmd &= 0x8F;
1869 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001870 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301871 break;
1872
1873 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 /* 1030 Chip Fix. Disable Split transactions
1875 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1876 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 if (revision < C0_1030) {
1878 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1879 pcixcmd &= 0x8F;
1880 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1881 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301882
1883 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001884 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301885 break;
1886
1887 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1888 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001889 ioc->errata_flag_1064 = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301890 ioc->bus_type = SAS;
1891 break;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301892
1893 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1894 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1895 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001896 ioc->bus_type = SAS;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301897 break;
Eric Moore87cf8982006-06-27 16:09:26 -06001898 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301900
Kashyap, Desaie3829682009-01-08 14:27:16 +05301901 switch (ioc->bus_type) {
1902
1903 case SAS:
1904 ioc->msi_enable = mpt_msi_enable_sas;
1905 break;
1906
1907 case SPI:
1908 ioc->msi_enable = mpt_msi_enable_spi;
1909 break;
1910
1911 case FC:
1912 ioc->msi_enable = mpt_msi_enable_fc;
1913 break;
1914
1915 default:
1916 ioc->msi_enable = 0;
1917 break;
1918 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001919 if (ioc->errata_flag_1064)
1920 pci_disable_io_access(pdev);
1921
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 spin_lock_init(&ioc->FreeQlock);
1923
1924 /* Disable all! */
1925 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1926 ioc->active = 0;
1927 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1928
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301929 /* Set IOC ptr in the pcidev's driver data. */
1930 pci_set_drvdata(ioc->pcidev, ioc);
1931
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 /* Set lookup ptr. */
1933 list_add_tail(&ioc->list, &ioc_list);
1934
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001935 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 */
1937 mpt_detect_bound_ports(ioc, pdev);
1938
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301939 INIT_LIST_HEAD(&ioc->fw_event_list);
1940 spin_lock_init(&ioc->fw_event_lock);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301941 snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301942 ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
1943
James Bottomleyc92f2222006-03-01 09:02:49 -06001944 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1945 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001946 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1947 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001948
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001950 if (ioc->alt_ioc)
1951 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301952 iounmap(ioc->memmap);
1953 if (r != -5)
1954 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301955
1956 destroy_workqueue(ioc->reset_work_q);
1957 ioc->reset_work_q = NULL;
1958
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 kfree(ioc);
1960 pci_set_drvdata(pdev, NULL);
1961 return r;
1962 }
1963
1964 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001965 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301966 if(MptDeviceDriverHandlers[cb_idx] &&
1967 MptDeviceDriverHandlers[cb_idx]->probe) {
1968 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 }
1970 }
1971
1972#ifdef CONFIG_PROC_FS
1973 /*
1974 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1975 */
1976 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1977 if (dent) {
1978 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1979 if (ent) {
1980 ent->read_proc = procmpt_iocinfo_read;
1981 ent->data = ioc;
1982 }
1983 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1984 if (ent) {
1985 ent->read_proc = procmpt_summary_read;
1986 ent->data = ioc;
1987 }
1988 }
1989#endif
1990
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301991 if (!ioc->alt_ioc)
1992 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1993 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1994
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 return 0;
1996}
1997
1998/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001999/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002000 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 */
2003
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002004void
2005mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006{
2007 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2008 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302009 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302010 unsigned long flags;
2011 struct workqueue_struct *wq;
2012
2013 /*
2014 * Stop polling ioc for fault condition
2015 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302016 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302017 wq = ioc->reset_work_q;
2018 ioc->reset_work_q = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302019 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302020 cancel_delayed_work(&ioc->fault_reset_work);
2021 destroy_workqueue(wq);
2022
Kashyap, Desai3eb08222009-05-29 16:47:26 +05302023 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2024 wq = ioc->fw_event_q;
2025 ioc->fw_event_q = NULL;
2026 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2027 destroy_workqueue(wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028
2029 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2030 remove_proc_entry(pname, NULL);
2031 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2032 remove_proc_entry(pname, NULL);
2033 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2034 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002035
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002037 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302038 if(MptDeviceDriverHandlers[cb_idx] &&
2039 MptDeviceDriverHandlers[cb_idx]->remove) {
2040 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 }
2042 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002043
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 /* Disable interrupts! */
2045 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2046
2047 ioc->active = 0;
2048 synchronize_irq(pdev->irq);
2049
2050 /* Clear any lingering interrupt */
2051 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2052
2053 CHIPREG_READ32(&ioc->chip->IntStatus);
2054
2055 mpt_adapter_dispose(ioc);
2056
2057 pci_set_drvdata(pdev, NULL);
2058}
2059
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060/**************************************************************************
2061 * Power Management
2062 */
2063#ifdef CONFIG_PM
2064/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002065/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002066 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002067 * @pdev: Pointer to pci_dev structure
2068 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002070int
2071mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072{
2073 u32 device_state;
2074 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302076 device_state = pci_choose_state(pdev, state);
2077 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2078 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2079 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080
2081 /* put ioc into READY_STATE */
2082 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2083 printk(MYIOC_s_ERR_FMT
2084 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2085 }
2086
2087 /* disable interrupts */
2088 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2089 ioc->active = 0;
2090
2091 /* Clear any lingering interrupt */
2092 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2093
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302094 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002095 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302096 pci_disable_msi(ioc->pcidev);
2097 ioc->pci_irq = -1;
2098 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302100 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 return 0;
2103}
2104
2105/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002106/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002107 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002108 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002110int
2111mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112{
2113 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2114 u32 device_state = pdev->current_state;
2115 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302116 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002117
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302118 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2119 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2120 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302122 pci_set_power_state(pdev, PCI_D0);
2123 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302125 ioc->pcidev = pdev;
2126 err = mpt_mapresources(ioc);
2127 if (err)
2128 return err;
2129
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302130 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2131 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2132 ioc->add_sge = &mpt_add_sge_64bit_1078;
2133 else
2134 ioc->add_sge = &mpt_add_sge_64bit;
2135 ioc->add_chain = &mpt_add_chain_64bit;
2136 ioc->sg_addr_size = 8;
2137 } else {
2138
2139 ioc->add_sge = &mpt_add_sge;
2140 ioc->add_chain = &mpt_add_chain;
2141 ioc->sg_addr_size = 4;
2142 }
2143 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2144
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302145 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2146 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2147 CHIPREG_READ32(&ioc->chip->Doorbell));
2148
2149 /*
2150 * Errata workaround for SAS pci express:
2151 * Upon returning to the D0 state, the contents of the doorbell will be
2152 * stale data, and this will incorrectly signal to the host driver that
2153 * the firmware is ready to process mpt commands. The workaround is
2154 * to issue a diagnostic reset.
2155 */
2156 if (ioc->bus_type == SAS && (pdev->device ==
2157 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2158 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2159 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2160 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2161 ioc->name);
2162 goto out;
2163 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302164 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165
2166 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302167 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2168 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2169 CAN_SLEEP);
2170 if (recovery_state != 0)
2171 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2172 "error:[%x]\n", ioc->name, recovery_state);
2173 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302175 "pci-resume: success\n", ioc->name);
2176 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302178
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179}
2180#endif
2181
James Bottomley4ff42a62006-05-17 18:06:52 -05002182static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302183mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002184{
2185 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2186 ioc->bus_type != SPI) ||
2187 (MptDriverClass[index] == MPTFC_DRIVER &&
2188 ioc->bus_type != FC) ||
2189 (MptDriverClass[index] == MPTSAS_DRIVER &&
2190 ioc->bus_type != SAS))
2191 /* make sure we only call the relevant reset handler
2192 * for the bus */
2193 return 0;
2194 return (MptResetHandlers[index])(ioc, reset_phase);
2195}
2196
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002198/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2200 * @ioc: Pointer to MPT adapter structure
2201 * @reason: Event word / reason
2202 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2203 *
2204 * This routine performs all the steps necessary to bring the IOC
2205 * to a OPERATIONAL state.
2206 *
2207 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2208 * MPT adapter.
2209 *
2210 * Returns:
2211 * 0 for success
2212 * -1 if failed to get board READY
2213 * -2 if READY but IOCFacts Failed
2214 * -3 if READY but PrimeIOCFifos Failed
2215 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302216 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302217 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 */
2219static int
2220mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2221{
2222 int hard_reset_done = 0;
2223 int alt_ioc_ready = 0;
2224 int hard;
2225 int rc=0;
2226 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302227 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 int handlers;
2229 int ret = 0;
2230 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002231 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302232 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233
Eric Moore29dd3602007-09-14 18:46:51 -06002234 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2235 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236
2237 /* Disable reply interrupts (also blocks FreeQ) */
2238 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2239 ioc->active = 0;
2240
2241 if (ioc->alt_ioc) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302242 if (ioc->alt_ioc->active ||
2243 reason == MPT_HOSTEVENT_IOC_RECOVER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244 reset_alt_ioc_active = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302245 /* Disable alt-IOC's reply interrupts
2246 * (and FreeQ) for a bit
2247 **/
2248 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2249 0xFFFFFFFF);
2250 ioc->alt_ioc->active = 0;
2251 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 }
2253
2254 hard = 1;
2255 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2256 hard = 0;
2257
2258 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2259 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002260 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2261 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262
2263 if (reset_alt_ioc_active && ioc->alt_ioc) {
2264 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002265 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2266 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002267 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 ioc->alt_ioc->active = 1;
2269 }
2270
2271 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302272 printk(MYIOC_s_WARN_FMT
2273 "NOT READY WARNING!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302275 ret = -1;
2276 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 }
2278
2279 /* hard_reset_done = 0 if a soft reset was performed
2280 * and 1 if a hard reset was performed.
2281 */
2282 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2283 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2284 alt_ioc_ready = 1;
2285 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05302286 printk(MYIOC_s_WARN_FMT
2287 ": alt-ioc Not ready WARNING!\n",
2288 ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 }
2290
2291 for (ii=0; ii<5; ii++) {
2292 /* Get IOC facts! Allow 5 retries */
2293 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2294 break;
2295 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002296
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297
2298 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002299 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2300 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 ret = -2;
2302 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2303 MptDisplayIocCapabilities(ioc);
2304 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002305
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 if (alt_ioc_ready) {
2307 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302308 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302309 "Initial Alt IocFacts failed rc=%x\n",
2310 ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 /* Retry - alt IOC was initialized once
2312 */
2313 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2314 }
2315 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302316 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002317 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 alt_ioc_ready = 0;
2319 reset_alt_ioc_active = 0;
2320 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2321 MptDisplayIocCapabilities(ioc->alt_ioc);
2322 }
2323 }
2324
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302325 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2326 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2327 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2328 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2329 IORESOURCE_IO);
2330 if (pci_enable_device(ioc->pcidev))
2331 return -5;
2332 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2333 "mpt"))
2334 return -5;
2335 }
2336
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002337 /*
2338 * Device is reset now. It must have de-asserted the interrupt line
2339 * (if it was asserted) and it should be safe to register for the
2340 * interrupt now.
2341 */
2342 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2343 ioc->pci_irq = -1;
2344 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302345 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002346 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002347 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302348 else
2349 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002350 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002351 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002352 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002353 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Kashyap, Desai2f187862009-05-29 16:52:37 +05302354 "interrupt %d!\n",
2355 ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302356 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002357 pci_disable_msi(ioc->pcidev);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302358 ret = -EBUSY;
2359 goto out;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002360 }
2361 irq_allocated = 1;
2362 ioc->pci_irq = ioc->pcidev->irq;
2363 pci_set_master(ioc->pcidev); /* ?? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302364 pci_set_drvdata(ioc->pcidev, ioc);
2365 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2366 "installed at interrupt %d\n", ioc->name,
2367 ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002368 }
2369 }
2370
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 /* Prime reply & request queues!
2372 * (mucho alloc's) Must be done prior to
2373 * init as upper addresses are needed for init.
2374 * If fails, continue with alt-ioc processing
2375 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302376 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
2377 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2379 ret = -3;
2380
2381 /* May need to check/upload firmware & data here!
2382 * If fails, continue with alt-ioc processing
2383 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302384 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
2385 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2387 ret = -4;
2388// NEW!
2389 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302390 printk(MYIOC_s_WARN_FMT
2391 ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002392 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393 alt_ioc_ready = 0;
2394 reset_alt_ioc_active = 0;
2395 }
2396
2397 if (alt_ioc_ready) {
2398 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2399 alt_ioc_ready = 0;
2400 reset_alt_ioc_active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302401 printk(MYIOC_s_WARN_FMT
2402 ": alt-ioc: (%d) init failure WARNING!\n",
2403 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 }
2405 }
2406
2407 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2408 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302409 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002410 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411
2412 /* Controller is not operational, cannot do upload
2413 */
2414 if (ret == 0) {
2415 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002416 if (rc == 0) {
2417 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2418 /*
2419 * Maintain only one pointer to FW memory
2420 * so there will not be two attempt to
2421 * downloadboot onboard dual function
2422 * chips (mpt_adapter_disable,
2423 * mpt_diag_reset)
2424 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302425 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002426 "mpt_upload: alt_%s has cached_fw=%p \n",
2427 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302428 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002429 }
2430 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002431 printk(MYIOC_s_WARN_FMT
2432 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302433 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002434 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 }
2436 }
2437 }
2438
Kashyap, Desaifd761752009-05-29 16:39:06 +05302439 /* Enable MPT base driver management of EventNotification
2440 * and EventAck handling.
2441 */
2442 if ((ret == 0) && (!ioc->facts.EventState)) {
2443 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2444 "SendEventNotification\n",
2445 ioc->name));
2446 ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
2447 }
2448
2449 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2450 rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
2451
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 if (ret == 0) {
2453 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002454 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 ioc->active = 1;
2456 }
Kashyap, Desaifd761752009-05-29 16:39:06 +05302457 if (rc == 0) { /* alt ioc */
2458 if (reset_alt_ioc_active && ioc->alt_ioc) {
2459 /* (re)Enable alt-IOC! (reply interrupt) */
2460 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
2461 "reply irq re-enabled\n",
2462 ioc->alt_ioc->name));
2463 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2464 MPI_HIM_DIM);
2465 ioc->alt_ioc->active = 1;
2466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 }
2468
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002470 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2472 * recursive scenario; GetLanConfigPages times out, timer expired
2473 * routine calls HardResetHandler, which calls into here again,
2474 * and we try GetLanConfigPages again...
2475 */
2476 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002477
2478 /*
2479 * Initalize link list for inactive raid volumes.
2480 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002481 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002482 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2483
Kashyap, Desai2f187862009-05-29 16:52:37 +05302484 switch (ioc->bus_type) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002485
Kashyap, Desai2f187862009-05-29 16:52:37 +05302486 case SAS:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002487 /* clear persistency table */
2488 if(ioc->facts.IOCExceptions &
2489 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2490 ret = mptbase_sas_persist_operation(ioc,
2491 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2492 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002493 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002494 }
2495
2496 /* Find IM volumes
2497 */
2498 mpt_findImVolumes(ioc);
2499
Kashyap, Desai2f187862009-05-29 16:52:37 +05302500 /* Check, and possibly reset, the coalescing value
2501 */
2502 mpt_read_ioc_pg_1(ioc);
2503
2504 break;
2505
2506 case FC:
2507 if ((ioc->pfacts[0].ProtocolFlags &
2508 MPI_PORTFACTS_PROTOCOL_LAN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2510 /*
2511 * Pre-fetch the ports LAN MAC address!
2512 * (LANPage1_t stuff)
2513 */
2514 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302515 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2516 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302517 "LanAddr = %02X:%02X:%02X"
2518 ":%02X:%02X:%02X\n",
2519 ioc->name, a[5], a[4],
2520 a[3], a[2], a[1], a[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302522 break;
2523
2524 case SPI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 /* Get NVRAM and adapter maximums from SPP 0 and 2
2526 */
2527 mpt_GetScsiPortSettings(ioc, 0);
2528
2529 /* Get version and length of SDP 1
2530 */
2531 mpt_readScsiDevicePageHeaders(ioc, 0);
2532
2533 /* Find IM volumes
2534 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002535 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 mpt_findImVolumes(ioc);
2537
2538 /* Check, and possibly reset, the coalescing value
2539 */
2540 mpt_read_ioc_pg_1(ioc);
2541
2542 mpt_read_ioc_pg_4(ioc);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302543
2544 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 }
2546
2547 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302548 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 }
2550
2551 /*
2552 * Call each currently registered protocol IOC reset handler
2553 * with post-reset indication.
2554 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2555 * MptResetHandlers[] registered yet.
2556 */
2557 if (hard_reset_done) {
2558 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302559 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2560 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302561 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002562 "Calling IOC post_reset handler #%d\n",
2563 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302564 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 handlers++;
2566 }
2567
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302568 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302569 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002570 "Calling IOC post_reset handler #%d\n",
2571 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302572 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 handlers++;
2574 }
2575 }
2576 /* FIXME? Examine results here? */
2577 }
2578
Eric Moore0ccdb002006-07-11 17:33:13 -06002579 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002580 if ((ret != 0) && irq_allocated) {
2581 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302582 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002583 pci_disable_msi(ioc->pcidev);
2584 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 return ret;
2586}
2587
2588/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002589/**
2590 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 * @ioc: Pointer to MPT adapter structure
2592 * @pdev: Pointer to (struct pci_dev) structure
2593 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002594 * Search for PCI bus/dev_function which matches
2595 * PCI bus/dev_function (+/-1) for newly discovered 929,
2596 * 929X, 1030 or 1035.
2597 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2599 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2600 */
2601static void
2602mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2603{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002604 struct pci_dev *peer=NULL;
2605 unsigned int slot = PCI_SLOT(pdev->devfn);
2606 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 MPT_ADAPTER *ioc_srch;
2608
Prakash, Sathya436ace72007-07-24 15:42:08 +05302609 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002610 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002611 ioc->name, pci_name(pdev), pdev->bus->number,
2612 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002613
2614 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2615 if (!peer) {
2616 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2617 if (!peer)
2618 return;
2619 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620
2621 list_for_each_entry(ioc_srch, &ioc_list, list) {
2622 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002623 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 /* Paranoia checks */
2625 if (ioc->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302626 printk(MYIOC_s_WARN_FMT
2627 "Oops, already bound (%s <==> %s)!\n",
2628 ioc->name, ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 break;
2630 } else if (ioc_srch->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302631 printk(MYIOC_s_WARN_FMT
2632 "Oops, already bound (%s <==> %s)!\n",
2633 ioc_srch->name, ioc_srch->name,
2634 ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 break;
2636 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302637 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2638 "FOUND! binding %s <==> %s\n",
2639 ioc->name, ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 ioc_srch->alt_ioc = ioc;
2641 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 }
2643 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002644 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645}
2646
2647/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002648/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002650 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 */
2652static void
2653mpt_adapter_disable(MPT_ADAPTER *ioc)
2654{
2655 int sz;
2656 int ret;
2657
2658 if (ioc->cached_fw != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302659 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2660 "%s: Pushing FW onto adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302661 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2662 ioc->cached_fw, CAN_SLEEP)) < 0) {
2663 printk(MYIOC_s_WARN_FMT
2664 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002665 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 }
2667 }
2668
Kashyap, Desai71278192009-05-29 16:53:14 +05302669 /*
2670 * Put the controller into ready state (if its not already)
2671 */
2672 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {
2673 if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
2674 CAN_SLEEP)) {
2675 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)
2676 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit "
2677 "reset failed to put ioc in ready state!\n",
2678 ioc->name, __func__);
2679 } else
2680 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset "
2681 "failed!\n", ioc->name, __func__);
2682 }
2683
2684
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 /* Disable adapter interrupts! */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302686 synchronize_irq(ioc->pcidev->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2688 ioc->active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302689
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 /* Clear any lingering interrupt */
2691 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302692 CHIPREG_READ32(&ioc->chip->IntStatus);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693
2694 if (ioc->alloc != NULL) {
2695 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002696 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2697 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 pci_free_consistent(ioc->pcidev, sz,
2699 ioc->alloc, ioc->alloc_dma);
2700 ioc->reply_frames = NULL;
2701 ioc->req_frames = NULL;
2702 ioc->alloc = NULL;
2703 ioc->alloc_total -= sz;
2704 }
2705
2706 if (ioc->sense_buf_pool != NULL) {
2707 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2708 pci_free_consistent(ioc->pcidev, sz,
2709 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2710 ioc->sense_buf_pool = NULL;
2711 ioc->alloc_total -= sz;
2712 }
2713
2714 if (ioc->events != NULL){
2715 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2716 kfree(ioc->events);
2717 ioc->events = NULL;
2718 ioc->alloc_total -= sz;
2719 }
2720
Prakash, Sathya984621b2008-01-11 14:42:17 +05302721 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002723 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002724 mpt_inactive_raid_list_free(ioc);
2725 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002726 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002727 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002728 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729
2730 if (ioc->spi_data.pIocPg4 != NULL) {
2731 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302732 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 ioc->spi_data.pIocPg4,
2734 ioc->spi_data.IocPg4_dma);
2735 ioc->spi_data.pIocPg4 = NULL;
2736 ioc->alloc_total -= sz;
2737 }
2738
2739 if (ioc->ReqToChain != NULL) {
2740 kfree(ioc->ReqToChain);
2741 kfree(ioc->RequestNB);
2742 ioc->ReqToChain = NULL;
2743 }
2744
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002745 kfree(ioc->ChainToChain);
2746 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002747
2748 if (ioc->HostPageBuffer != NULL) {
2749 if((ret = mpt_host_page_access_control(ioc,
2750 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002751 printk(MYIOC_s_ERR_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302752 ": %s: host page buffers free failed (%d)!\n",
2753 ioc->name, __func__, ret);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002754 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302755 dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2756 "HostPageBuffer free @ %p, sz=%d bytes\n",
2757 ioc->name, ioc->HostPageBuffer,
2758 ioc->HostPageBuffer_sz));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002759 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002760 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002761 ioc->HostPageBuffer = NULL;
2762 ioc->HostPageBuffer_sz = 0;
2763 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2764 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765
Kashyap, Desai2f187862009-05-29 16:52:37 +05302766 pci_set_drvdata(ioc->pcidev, NULL);
2767}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002769/**
2770 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 * @ioc: Pointer to MPT adapter structure
2772 *
2773 * This routine unregisters h/w resources and frees all alloc'd memory
2774 * associated with a MPT adapter structure.
2775 */
2776static void
2777mpt_adapter_dispose(MPT_ADAPTER *ioc)
2778{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002779 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002781 if (ioc == NULL)
2782 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002784 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002786 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002788 if (ioc->pci_irq != -1) {
2789 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302790 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002791 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002792 ioc->pci_irq = -1;
2793 }
2794
2795 if (ioc->memmap != NULL) {
2796 iounmap(ioc->memmap);
2797 ioc->memmap = NULL;
2798 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302800 pci_disable_device(ioc->pcidev);
2801 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2802
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002804 if (ioc->mtrr_reg > 0) {
2805 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002806 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002807 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808#endif
2809
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002810 /* Zap the adapter lookup ptr! */
2811 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002813 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002814 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2815 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002816
2817 if (ioc->alt_ioc)
2818 ioc->alt_ioc->alt_ioc = NULL;
2819
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002820 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821}
2822
2823/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002824/**
2825 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 * @ioc: Pointer to MPT adapter structure
2827 */
2828static void
2829MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2830{
2831 int i = 0;
2832
2833 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302834 if (ioc->prod_name)
2835 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 printk("Capabilities={");
2837
2838 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2839 printk("Initiator");
2840 i++;
2841 }
2842
2843 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2844 printk("%sTarget", i ? "," : "");
2845 i++;
2846 }
2847
2848 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2849 printk("%sLAN", i ? "," : "");
2850 i++;
2851 }
2852
2853#if 0
2854 /*
2855 * This would probably evoke more questions than it's worth
2856 */
2857 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2858 printk("%sLogBusAddr", i ? "," : "");
2859 i++;
2860 }
2861#endif
2862
2863 printk("}\n");
2864}
2865
2866/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002867/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2869 * @ioc: Pointer to MPT_ADAPTER structure
2870 * @force: Force hard KickStart of IOC
2871 * @sleepFlag: Specifies whether the process can sleep
2872 *
2873 * Returns:
2874 * 1 - DIAG reset and READY
2875 * 0 - READY initially OR soft reset and READY
2876 * -1 - Any failure on KickStart
2877 * -2 - Msg Unit Reset Failed
2878 * -3 - IO Unit Reset Failed
2879 * -4 - IOC owned by a PEER
2880 */
2881static int
2882MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2883{
2884 u32 ioc_state;
2885 int statefault = 0;
2886 int cntdn;
2887 int hard_reset_done = 0;
2888 int r;
2889 int ii;
2890 int whoinit;
2891
2892 /* Get current [raw] IOC state */
2893 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002894 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895
2896 /*
2897 * Check to see if IOC got left/stuck in doorbell handshake
2898 * grip of death. If so, hard reset the IOC.
2899 */
2900 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2901 statefault = 1;
2902 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2903 ioc->name);
2904 }
2905
2906 /* Is it already READY? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302907 if (!statefault &&
2908 ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) {
2909 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2910 "IOC is in READY state\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 return 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302912 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913
2914 /*
2915 * Check to see if IOC is in FAULT state.
2916 */
2917 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2918 statefault = 2;
2919 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002920 ioc->name);
2921 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2922 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 }
2924
2925 /*
2926 * Hmmm... Did it get left operational?
2927 */
2928 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302929 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 ioc->name));
2931
2932 /* Check WhoInit.
2933 * If PCI Peer, exit.
2934 * Else, if no fault conditions are present, issue a MessageUnitReset
2935 * Else, fall through to KickStart case
2936 */
2937 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002938 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2939 "whoinit 0x%x statefault %d force %d\n",
2940 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941 if (whoinit == MPI_WHOINIT_PCI_PEER)
2942 return -4;
2943 else {
2944 if ((statefault == 0 ) && (force == 0)) {
2945 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2946 return 0;
2947 }
2948 statefault = 3;
2949 }
2950 }
2951
2952 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2953 if (hard_reset_done < 0)
2954 return -1;
2955
2956 /*
2957 * Loop here waiting for IOC to come READY.
2958 */
2959 ii = 0;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002960 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961
2962 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2963 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2964 /*
2965 * BIOS or previous driver load left IOC in OP state.
2966 * Reset messaging FIFOs.
2967 */
2968 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2969 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2970 return -2;
2971 }
2972 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2973 /*
2974 * Something is wrong. Try to get IOC back
2975 * to a known state.
2976 */
2977 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2978 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2979 return -3;
2980 }
2981 }
2982
2983 ii++; cntdn--;
2984 if (!cntdn) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302985 printk(MYIOC_s_ERR_FMT
2986 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
2987 ioc->name, ioc_state, (int)((ii+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 return -ETIME;
2989 }
2990
2991 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002992 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 } else {
2994 mdelay (1); /* 1 msec delay */
2995 }
2996
2997 }
2998
2999 if (statefault < 3) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303000 printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name,
3001 statefault == 1 ? "stuck handshake" : "IOC FAULT");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 }
3003
3004 return hard_reset_done;
3005}
3006
3007/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003008/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 * mpt_GetIocState - Get the current state of a MPT adapter.
3010 * @ioc: Pointer to MPT_ADAPTER structure
3011 * @cooked: Request raw or cooked IOC state
3012 *
3013 * Returns all IOC Doorbell register bits if cooked==0, else just the
3014 * Doorbell bits in MPI_IOC_STATE_MASK.
3015 */
3016u32
3017mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
3018{
3019 u32 s, sc;
3020
3021 /* Get! */
3022 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 sc = s & MPI_IOC_STATE_MASK;
3024
3025 /* Save! */
3026 ioc->last_state = sc;
3027
3028 return cooked ? sc : s;
3029}
3030
3031/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003032/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 * GetIocFacts - Send IOCFacts request to MPT adapter.
3034 * @ioc: Pointer to MPT_ADAPTER structure
3035 * @sleepFlag: Specifies whether the process can sleep
3036 * @reason: If recovery, only update facts.
3037 *
3038 * Returns 0 for success, non-zero for failure.
3039 */
3040static int
3041GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
3042{
3043 IOCFacts_t get_facts;
3044 IOCFactsReply_t *facts;
3045 int r;
3046 int req_sz;
3047 int reply_sz;
3048 int sz;
3049 u32 status, vv;
3050 u8 shiftFactor=1;
3051
3052 /* IOC *must* NOT be in RESET state! */
3053 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303054 printk(KERN_ERR MYNAM
3055 ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
3056 ioc->name, ioc->last_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 return -44;
3058 }
3059
3060 facts = &ioc->facts;
3061
3062 /* Destination (reply area)... */
3063 reply_sz = sizeof(*facts);
3064 memset(facts, 0, reply_sz);
3065
3066 /* Request area (get_facts on the stack right now!) */
3067 req_sz = sizeof(get_facts);
3068 memset(&get_facts, 0, req_sz);
3069
3070 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
3071 /* Assert: All other get_facts fields are zero! */
3072
Prakash, Sathya436ace72007-07-24 15:42:08 +05303073 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003074 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 ioc->name, req_sz, reply_sz));
3076
3077 /* No non-zero fields in the get_facts request are greater than
3078 * 1 byte in size, so we can just fire it off as is.
3079 */
3080 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3081 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3082 if (r != 0)
3083 return r;
3084
3085 /*
3086 * Now byte swap (GRRR) the necessary fields before any further
3087 * inspection of reply contents.
3088 *
3089 * But need to do some sanity checks on MsgLength (byte) field
3090 * to make sure we don't zero IOC's req_sz!
3091 */
3092 /* Did we get a valid reply? */
3093 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3094 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3095 /*
3096 * If not been here, done that, save off first WhoInit value
3097 */
3098 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3099 ioc->FirstWhoInit = facts->WhoInit;
3100 }
3101
3102 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3103 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3104 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3105 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3106 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003107 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 /* CHECKME! IOCStatus, IOCLogInfo */
3109
3110 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3111 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3112
3113 /*
3114 * FC f/w version changed between 1.1 and 1.2
3115 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3116 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3117 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303118 if (facts->MsgVersion < MPI_VERSION_01_02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119 /*
3120 * Handle old FC f/w style, convert to new...
3121 */
3122 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3123 facts->FWVersion.Word =
3124 ((oldv<<12) & 0xFF000000) |
3125 ((oldv<<8) & 0x000FFF00);
3126 } else
3127 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3128
3129 facts->ProductID = le16_to_cpu(facts->ProductID);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303130
Eric Mooreb506ade2007-01-29 09:45:37 -07003131 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3132 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3133 ioc->ir_firmware = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303134
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 facts->CurrentHostMfaHighAddr =
3136 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3137 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3138 facts->CurrentSenseBufferHighAddr =
3139 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3140 facts->CurReplyFrameSize =
3141 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003142 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143
3144 /*
3145 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3146 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3147 * to 14 in MPI-1.01.0x.
3148 */
3149 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
Kashyap, Desai2f187862009-05-29 16:52:37 +05303150 facts->MsgVersion > MPI_VERSION_01_00) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3152 }
3153
3154 sz = facts->FWImageSize;
3155 if ( sz & 0x01 )
3156 sz += 1;
3157 if ( sz & 0x02 )
3158 sz += 2;
3159 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003160
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 if (!facts->RequestFrameSize) {
3162 /* Something is wrong! */
3163 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3164 ioc->name);
3165 return -55;
3166 }
3167
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003168 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 vv = ((63 / (sz * 4)) + 1) & 0x03;
3170 ioc->NB_for_64_byte_frame = vv;
3171 while ( sz )
3172 {
3173 shiftFactor++;
3174 sz = sz >> 1;
3175 }
3176 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303177 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003178 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3179 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003180
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3182 /*
3183 * Set values for this IOC's request & reply frame sizes,
3184 * and request & reply queue depths...
3185 */
3186 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3187 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3188 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3189 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3190
Prakash, Sathya436ace72007-07-24 15:42:08 +05303191 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303193 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 ioc->name, ioc->req_sz, ioc->req_depth));
3195
3196 /* Get port facts! */
3197 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3198 return r;
3199 }
3200 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003201 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3203 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3204 RequestFrameSize)/sizeof(u32)));
3205 return -66;
3206 }
3207
3208 return 0;
3209}
3210
3211/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003212/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 * GetPortFacts - Send PortFacts request to MPT adapter.
3214 * @ioc: Pointer to MPT_ADAPTER structure
3215 * @portnum: Port number
3216 * @sleepFlag: Specifies whether the process can sleep
3217 *
3218 * Returns 0 for success, non-zero for failure.
3219 */
3220static int
3221GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3222{
3223 PortFacts_t get_pfacts;
3224 PortFactsReply_t *pfacts;
3225 int ii;
3226 int req_sz;
3227 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003228 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229
3230 /* IOC *must* NOT be in RESET state! */
3231 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003232 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3233 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 return -4;
3235 }
3236
3237 pfacts = &ioc->pfacts[portnum];
3238
3239 /* Destination (reply area)... */
3240 reply_sz = sizeof(*pfacts);
3241 memset(pfacts, 0, reply_sz);
3242
3243 /* Request area (get_pfacts on the stack right now!) */
3244 req_sz = sizeof(get_pfacts);
3245 memset(&get_pfacts, 0, req_sz);
3246
3247 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3248 get_pfacts.PortNumber = portnum;
3249 /* Assert: All other get_pfacts fields are zero! */
3250
Prakash, Sathya436ace72007-07-24 15:42:08 +05303251 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252 ioc->name, portnum));
3253
3254 /* No non-zero fields in the get_pfacts request are greater than
3255 * 1 byte in size, so we can just fire it off as is.
3256 */
3257 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3258 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3259 if (ii != 0)
3260 return ii;
3261
3262 /* Did we get a valid reply? */
3263
3264 /* Now byte swap the necessary fields in the response. */
3265 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3266 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3267 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3268 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3269 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3270 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3271 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3272 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3273 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3274
Eric Moore793955f2007-01-29 09:42:20 -07003275 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3276 pfacts->MaxDevices;
3277 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3278 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3279
3280 /*
3281 * Place all the devices on channels
3282 *
3283 * (for debuging)
3284 */
3285 if (mpt_channel_mapping) {
3286 ioc->devices_per_bus = 1;
3287 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3288 }
3289
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 return 0;
3291}
3292
3293/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003294/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 * SendIocInit - Send IOCInit request to MPT adapter.
3296 * @ioc: Pointer to MPT_ADAPTER structure
3297 * @sleepFlag: Specifies whether the process can sleep
3298 *
3299 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3300 *
3301 * Returns 0 for success, non-zero for failure.
3302 */
3303static int
3304SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3305{
3306 IOCInit_t ioc_init;
3307 MPIDefaultReply_t init_reply;
3308 u32 state;
3309 int r;
3310 int count;
3311 int cntdn;
3312
3313 memset(&ioc_init, 0, sizeof(ioc_init));
3314 memset(&init_reply, 0, sizeof(init_reply));
3315
3316 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3317 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3318
3319 /* If we are in a recovery mode and we uploaded the FW image,
3320 * then this pointer is not NULL. Skip the upload a second time.
3321 * Set this flag if cached_fw set for either IOC.
3322 */
3323 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3324 ioc->upload_fw = 1;
3325 else
3326 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303327 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3329
Eric Moore793955f2007-01-29 09:42:20 -07003330 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3331 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303332
Prakash, Sathya436ace72007-07-24 15:42:08 +05303333 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003334 ioc->name, ioc->facts.MsgVersion));
3335 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3336 // set MsgVersion and HeaderVersion host driver was built with
3337 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3338 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003340 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3341 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3342 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3343 return -99;
3344 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3346
Kashyap, Desai2f187862009-05-29 16:52:37 +05303347 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 /* Save the upper 32-bits of the request
3349 * (reply) and sense buffers.
3350 */
3351 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3352 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3353 } else {
3354 /* Force 32-bit addressing */
3355 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3356 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3357 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003358
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3360 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003361 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3362 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363
Prakash, Sathya436ace72007-07-24 15:42:08 +05303364 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 ioc->name, &ioc_init));
3366
3367 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3368 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003369 if (r != 0) {
3370 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 return r;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003372 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373
3374 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003375 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 */
3377
Prakash, Sathya436ace72007-07-24 15:42:08 +05303378 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003380
3381 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3382 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385
3386 /* YIKES! SUPER IMPORTANT!!!
3387 * Poll IocState until _OPERATIONAL while IOC is doing
3388 * LoopInit and TargetDiscovery!
3389 */
3390 count = 0;
3391 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3392 state = mpt_GetIocState(ioc, 1);
3393 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3394 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003395 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 } else {
3397 mdelay(1);
3398 }
3399
3400 if (!cntdn) {
3401 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3402 ioc->name, (int)((count+5)/HZ));
3403 return -9;
3404 }
3405
3406 state = mpt_GetIocState(ioc, 1);
3407 count++;
3408 }
Eric Moore29dd3602007-09-14 18:46:51 -06003409 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 ioc->name, count));
3411
Eric Mooreba856d32006-07-11 17:34:01 -06003412 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 return r;
3414}
3415
3416/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003417/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 * SendPortEnable - Send PortEnable request to MPT adapter port.
3419 * @ioc: Pointer to MPT_ADAPTER structure
3420 * @portnum: Port number to enable
3421 * @sleepFlag: Specifies whether the process can sleep
3422 *
3423 * Send PortEnable to bring IOC to OPERATIONAL state.
3424 *
3425 * Returns 0 for success, non-zero for failure.
3426 */
3427static int
3428SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3429{
3430 PortEnable_t port_enable;
3431 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003432 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 int req_sz;
3434 int reply_sz;
3435
3436 /* Destination... */
3437 reply_sz = sizeof(MPIDefaultReply_t);
3438 memset(&reply_buf, 0, reply_sz);
3439
3440 req_sz = sizeof(PortEnable_t);
3441 memset(&port_enable, 0, req_sz);
3442
3443 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3444 port_enable.PortNumber = portnum;
3445/* port_enable.ChainOffset = 0; */
3446/* port_enable.MsgFlags = 0; */
3447/* port_enable.MsgContext = 0; */
3448
Prakash, Sathya436ace72007-07-24 15:42:08 +05303449 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 ioc->name, portnum, &port_enable));
3451
3452 /* RAID FW may take a long time to enable
3453 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003454 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003455 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3456 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3457 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003458 } else {
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 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003463 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464}
3465
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003466/**
3467 * mpt_alloc_fw_memory - allocate firmware memory
3468 * @ioc: Pointer to MPT_ADAPTER structure
3469 * @size: total FW bytes
3470 *
3471 * If memory has already been allocated, the same (cached) value
3472 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303473 *
3474 * Return 0 if successfull, or non-zero for failure
3475 **/
3476int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3478{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303479 int rc;
3480
3481 if (ioc->cached_fw) {
3482 rc = 0; /* use already allocated memory */
3483 goto out;
3484 }
3485 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3487 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303488 rc = 0;
3489 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303491 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3492 if (!ioc->cached_fw) {
3493 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3494 ioc->name);
3495 rc = -1;
3496 } else {
3497 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3498 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3499 ioc->alloc_total += size;
3500 rc = 0;
3501 }
3502 out:
3503 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303505
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003506/**
3507 * mpt_free_fw_memory - free firmware memory
3508 * @ioc: Pointer to MPT_ADAPTER structure
3509 *
3510 * If alt_img is NULL, delete from ioc structure.
3511 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303512 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513void
3514mpt_free_fw_memory(MPT_ADAPTER *ioc)
3515{
3516 int sz;
3517
Prakash, Sathya984621b2008-01-11 14:42:17 +05303518 if (!ioc->cached_fw)
3519 return;
3520
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303522 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3523 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003524 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303525 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527}
3528
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003530/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3532 * @ioc: Pointer to MPT_ADAPTER structure
3533 * @sleepFlag: Specifies whether the process can sleep
3534 *
3535 * Returns 0 for success, >0 for handshake failure
3536 * <0 for fw upload failure.
3537 *
3538 * Remark: If bound IOC and a successful FWUpload was performed
3539 * on the bound IOC, the second image is discarded
3540 * and memory is free'd. Both channels must upload to prevent
3541 * IOC from running in degraded mode.
3542 */
3543static int
3544mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3545{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 u8 reply[sizeof(FWUploadReply_t)];
3547 FWUpload_t *prequest;
3548 FWUploadReply_t *preply;
3549 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550 u32 flagsLength;
3551 int ii, sz, reply_sz;
3552 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303553 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554 /* If the image size is 0, we are done.
3555 */
3556 if ((sz = ioc->facts.FWImageSize) == 0)
3557 return 0;
3558
Prakash, Sathya984621b2008-01-11 14:42:17 +05303559 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3560 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561
Eric Moore29dd3602007-09-14 18:46:51 -06003562 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3563 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003564
Eric Moorebc6e0892007-09-29 10:16:28 -06003565 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3566 kzalloc(ioc->req_sz, GFP_KERNEL);
3567 if (!prequest) {
3568 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3569 "while allocating memory \n", ioc->name));
3570 mpt_free_fw_memory(ioc);
3571 return -ENOMEM;
3572 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573
Eric Moorebc6e0892007-09-29 10:16:28 -06003574 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575
3576 reply_sz = sizeof(reply);
3577 memset(preply, 0, reply_sz);
3578
3579 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3580 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3581
3582 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3583 ptcsge->DetailsLength = 12;
3584 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3585 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003586 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303589 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3590 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3591 ioc->SGE_size;
3592 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3593 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3594 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003595 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303597 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3598 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599
Kashyap, Desai2f187862009-05-29 16:52:37 +05303600 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
3601 "rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602
3603 cmdStatus = -EFAULT;
3604 if (ii == 0) {
3605 /* Handshake transfer was complete and successful.
3606 * Check the Reply Frame.
3607 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303608 int status;
3609 status = le16_to_cpu(preply->IOCStatus) &
3610 MPI_IOCSTATUS_MASK;
3611 if (status == MPI_IOCSTATUS_SUCCESS &&
3612 ioc->facts.FWImageSize ==
3613 le32_to_cpu(preply->ActualImageSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614 cmdStatus = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303616 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 ioc->name, cmdStatus));
3618
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003619
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 if (cmdStatus) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303621 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
3622 "freeing image \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 mpt_free_fw_memory(ioc);
3624 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003625 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626
3627 return cmdStatus;
3628}
3629
3630/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003631/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632 * mpt_downloadboot - DownloadBoot code
3633 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003634 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 * @sleepFlag: Specifies whether the process can sleep
3636 *
3637 * FwDownloadBoot requires Programmed IO access.
3638 *
3639 * Returns 0 for success
3640 * -1 FW Image size is 0
3641 * -2 No valid cached_fw Pointer
3642 * <0 for fw upload failure.
3643 */
3644static int
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003645mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647 MpiExtImageHeader_t *pExtImage;
3648 u32 fwSize;
3649 u32 diag0val;
3650 int count;
3651 u32 *ptrFw;
3652 u32 diagRwData;
3653 u32 nextImage;
3654 u32 load_addr;
3655 u32 ioc_state=0;
3656
Prakash, Sathya436ace72007-07-24 15:42:08 +05303657 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003658 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003659
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3661 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3662 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3663 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3664 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3665 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3666
3667 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3668
3669 /* wait 1 msec */
3670 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003671 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672 } else {
3673 mdelay (1);
3674 }
3675
3676 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3677 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3678
3679 for (count = 0; count < 30; count ++) {
3680 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3681 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303682 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 ioc->name, count));
3684 break;
3685 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003686 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003688 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 } else {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003690 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 }
3692 }
3693
3694 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303695 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003696 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697 ioc->name, diag0val));
3698 return -3;
3699 }
3700
3701 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3702 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3703 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3704 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3705 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3706 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3707
3708 /* Set the DiagRwEn and Disable ARM bits */
3709 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3710
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 fwSize = (pFwHeader->ImageSize + 3)/4;
3712 ptrFw = (u32 *) pFwHeader;
3713
3714 /* Write the LoadStartAddress to the DiagRw Address Register
3715 * using Programmed IO
3716 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003717 if (ioc->errata_flag_1064)
3718 pci_enable_io_access(ioc->pcidev);
3719
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303721 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722 ioc->name, pFwHeader->LoadStartAddress));
3723
Prakash, Sathya436ace72007-07-24 15:42:08 +05303724 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725 ioc->name, fwSize*4, ptrFw));
3726 while (fwSize--) {
3727 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3728 }
3729
3730 nextImage = pFwHeader->NextImageHeaderOffset;
3731 while (nextImage) {
3732 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3733
3734 load_addr = pExtImage->LoadStartAddress;
3735
3736 fwSize = (pExtImage->ImageSize + 3) >> 2;
3737 ptrFw = (u32 *)pExtImage;
3738
Prakash, Sathya436ace72007-07-24 15:42:08 +05303739 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 +02003740 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3742
3743 while (fwSize--) {
3744 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3745 }
3746 nextImage = pExtImage->NextImageHeaderOffset;
3747 }
3748
3749 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303750 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3752
3753 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303754 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3756
3757 /* Clear the internal flash bad bit - autoincrementing register,
3758 * so must do two writes.
3759 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003760 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003761 /*
3762 * 1030 and 1035 H/W errata, workaround to access
3763 * the ClearFlashBadSignatureBit
3764 */
3765 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3766 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3767 diagRwData |= 0x40000000;
3768 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3769 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3770
3771 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3772 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3773 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3774 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3775
3776 /* wait 1 msec */
3777 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003778 msleep (1);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003779 } else {
3780 mdelay (1);
3781 }
3782 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003784 if (ioc->errata_flag_1064)
3785 pci_disable_io_access(ioc->pcidev);
3786
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303788 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003789 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 ioc->name, diag0val));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003791 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303792 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 ioc->name, diag0val));
3794 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3795
3796 /* Write 0xFF to reset the sequencer */
3797 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3798
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003799 if (ioc->bus_type == SAS) {
3800 ioc_state = mpt_GetIocState(ioc, 0);
3801 if ( (GetIocFacts(ioc, sleepFlag,
3802 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303803 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003804 ioc->name, ioc_state));
3805 return -EFAULT;
3806 }
3807 }
3808
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809 for (count=0; count<HZ*20; count++) {
3810 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303811 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3812 "downloadboot successful! (count=%d) IocState=%x\n",
3813 ioc->name, count, ioc_state));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003814 if (ioc->bus_type == SAS) {
3815 return 0;
3816 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303818 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3819 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820 ioc->name));
3821 return -EFAULT;
3822 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303823 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3824 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825 ioc->name));
3826 return 0;
3827 }
3828 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003829 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830 } else {
3831 mdelay (10);
3832 }
3833 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303834 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3835 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 return -EFAULT;
3837}
3838
3839/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003840/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 * KickStart - Perform hard reset of MPT adapter.
3842 * @ioc: Pointer to MPT_ADAPTER structure
3843 * @force: Force hard reset
3844 * @sleepFlag: Specifies whether the process can sleep
3845 *
3846 * This routine places MPT adapter in diagnostic mode via the
3847 * WriteSequence register, and then performs a hard reset of adapter
3848 * via the Diagnostic register.
3849 *
3850 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3851 * or NO_SLEEP (interrupt thread, use mdelay)
3852 * force - 1 if doorbell active, board fault state
3853 * board operational, IOC_RECOVERY or
3854 * IOC_BRINGUP and there is an alt_ioc.
3855 * 0 else
3856 *
3857 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003858 * 1 - hard reset, READY
3859 * 0 - no reset due to History bit, READY
3860 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861 * OR reset but failed to come READY
3862 * -2 - no reset, could not enter DIAG mode
3863 * -3 - reset but bad FW bit
3864 */
3865static int
3866KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3867{
3868 int hard_reset_done = 0;
3869 u32 ioc_state=0;
3870 int cnt,cntdn;
3871
Eric Moore29dd3602007-09-14 18:46:51 -06003872 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003873 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 /* Always issue a Msg Unit Reset first. This will clear some
3875 * SCSI bus hang conditions.
3876 */
3877 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3878
3879 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003880 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 } else {
3882 mdelay (1000);
3883 }
3884 }
3885
3886 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3887 if (hard_reset_done < 0)
3888 return hard_reset_done;
3889
Prakash, Sathya436ace72007-07-24 15:42:08 +05303890 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003891 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892
3893 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3894 for (cnt=0; cnt<cntdn; cnt++) {
3895 ioc_state = mpt_GetIocState(ioc, 1);
3896 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303897 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898 ioc->name, cnt));
3899 return hard_reset_done;
3900 }
3901 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003902 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 } else {
3904 mdelay (10);
3905 }
3906 }
3907
Eric Moore29dd3602007-09-14 18:46:51 -06003908 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3909 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910 return -1;
3911}
3912
3913/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003914/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 * mpt_diag_reset - Perform hard reset of the adapter.
3916 * @ioc: Pointer to MPT_ADAPTER structure
3917 * @ignore: Set if to honor and clear to ignore
3918 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003919 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 * else set to NO_SLEEP (use mdelay instead)
3921 *
3922 * This routine places the adapter in diagnostic mode via the
3923 * WriteSequence register and then performs a hard reset of adapter
3924 * via the Diagnostic register. Adapter should be in ready state
3925 * upon successful completion.
3926 *
3927 * Returns: 1 hard reset successful
3928 * 0 no reset performed because reset history bit set
3929 * -2 enabling diagnostic mode failed
3930 * -3 diagnostic reset failed
3931 */
3932static int
3933mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3934{
3935 u32 diag0val;
3936 u32 doorbell;
3937 int hard_reset_done = 0;
3938 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303940 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941
Eric Moorecd2c6192007-01-29 09:47:47 -07003942 /* Clear any existing interrupts */
3943 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3944
Eric Moore87cf8982006-06-27 16:09:26 -06003945 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303946
3947 if (!ignore)
3948 return 0;
3949
Prakash, Sathya436ace72007-07-24 15:42:08 +05303950 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003951 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003952 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3953 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3954 if (sleepFlag == CAN_SLEEP)
3955 msleep(1);
3956 else
3957 mdelay(1);
3958
3959 for (count = 0; count < 60; count ++) {
3960 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3961 doorbell &= MPI_IOC_STATE_MASK;
3962
Prakash, Sathya436ace72007-07-24 15:42:08 +05303963 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003964 "looking for READY STATE: doorbell=%x"
3965 " count=%d\n",
3966 ioc->name, doorbell, count));
Kashyap, Desai2f187862009-05-29 16:52:37 +05303967
Eric Moore87cf8982006-06-27 16:09:26 -06003968 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003969 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003970 }
3971
3972 /* wait 1 sec */
3973 if (sleepFlag == CAN_SLEEP)
3974 msleep(1000);
3975 else
3976 mdelay(1000);
3977 }
3978 return -1;
3979 }
3980
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981 /* Use "Diagnostic reset" method! (only thing available!) */
3982 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3983
Prakash, Sathya436ace72007-07-24 15:42:08 +05303984 if (ioc->debug_level & MPT_DEBUG) {
3985 if (ioc->alt_ioc)
3986 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3987 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303989 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990
3991 /* Do the reset if we are told to ignore the reset history
3992 * or if the reset history is 0
3993 */
3994 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3995 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3996 /* Write magic sequence to WriteSequence register
3997 * Loop until in diagnostic mode
3998 */
3999 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4000 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4001 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4002 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4003 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4004 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4005
4006 /* wait 100 msec */
4007 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004008 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 } else {
4010 mdelay (100);
4011 }
4012
4013 count++;
4014 if (count > 20) {
4015 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4016 ioc->name, diag0val);
4017 return -2;
4018
4019 }
4020
4021 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4022
Prakash, Sathya436ace72007-07-24 15:42:08 +05304023 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 ioc->name, diag0val));
4025 }
4026
Prakash, Sathya436ace72007-07-24 15:42:08 +05304027 if (ioc->debug_level & MPT_DEBUG) {
4028 if (ioc->alt_ioc)
4029 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4030 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304032 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 /*
4034 * Disable the ARM (Bug fix)
4035 *
4036 */
4037 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004038 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039
4040 /*
4041 * Now hit the reset bit in the Diagnostic register
4042 * (THE BIG HAMMER!) (Clears DRWE bit).
4043 */
4044 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
4045 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304046 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047 ioc->name));
4048
4049 /*
4050 * Call each currently registered protocol IOC reset handler
4051 * with pre-reset indication.
4052 * NOTE: If we're doing _IOC_BRINGUP, there can be no
4053 * MptResetHandlers[] registered yet.
4054 */
4055 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304056 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057 int r = 0;
4058
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304059 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
4060 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304061 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4062 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304063 ioc->name, cb_idx));
4064 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304066 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4067 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304068 ioc->name, ioc->alt_ioc->name, cb_idx));
4069 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070 }
4071 }
4072 }
4073 /* FIXME? Examine results here? */
4074 }
4075
Eric Moore0ccdb002006-07-11 17:33:13 -06004076 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304077 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06004078 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304079 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4080 else
4081 cached_fw = NULL;
4082 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083 /* If the DownloadBoot operation fails, the
4084 * IOC will be left unusable. This is a fatal error
4085 * case. _diag_reset will return < 0
4086 */
4087 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304088 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4090 break;
4091 }
4092
Prakash, Sathya436ace72007-07-24 15:42:08 +05304093 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304094 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095 /* wait 1 sec */
4096 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004097 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098 } else {
4099 mdelay (1000);
4100 }
4101 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304102 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004103 printk(MYIOC_s_WARN_FMT
4104 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105 }
4106
4107 } else {
4108 /* Wait for FW to reload and for board
4109 * to go to the READY state.
4110 * Maximum wait is 60 seconds.
4111 * If fail, no error will check again
4112 * with calling program.
4113 */
4114 for (count = 0; count < 60; count ++) {
4115 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4116 doorbell &= MPI_IOC_STATE_MASK;
4117
Kashyap, Desai2f187862009-05-29 16:52:37 +05304118 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4119 "looking for READY STATE: doorbell=%x"
4120 " count=%d\n", ioc->name, doorbell, count));
4121
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122 if (doorbell == MPI_IOC_STATE_READY) {
4123 break;
4124 }
4125
4126 /* wait 1 sec */
4127 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004128 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129 } else {
4130 mdelay (1000);
4131 }
4132 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05304133
4134 if (doorbell != MPI_IOC_STATE_READY)
4135 printk(MYIOC_s_ERR_FMT "Failed to come READY "
4136 "after reset! IocState=%x", ioc->name,
4137 doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 }
4139 }
4140
4141 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304142 if (ioc->debug_level & MPT_DEBUG) {
4143 if (ioc->alt_ioc)
4144 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4145 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4146 ioc->name, diag0val, diag1val));
4147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148
4149 /* Clear RESET_HISTORY bit! Place board in the
4150 * diagnostic mode to update the diag register.
4151 */
4152 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4153 count = 0;
4154 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4155 /* Write magic sequence to WriteSequence register
4156 * Loop until in diagnostic mode
4157 */
4158 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4159 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4160 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4161 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4162 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4163 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4164
4165 /* wait 100 msec */
4166 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004167 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 } else {
4169 mdelay (100);
4170 }
4171
4172 count++;
4173 if (count > 20) {
4174 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4175 ioc->name, diag0val);
4176 break;
4177 }
4178 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4179 }
4180 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4181 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4182 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4183 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4184 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4185 ioc->name);
4186 }
4187
4188 /* Disable Diagnostic Mode
4189 */
4190 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4191
4192 /* Check FW reload status flags.
4193 */
4194 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4195 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4196 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4197 ioc->name, diag0val);
4198 return -3;
4199 }
4200
Prakash, Sathya436ace72007-07-24 15:42:08 +05304201 if (ioc->debug_level & MPT_DEBUG) {
4202 if (ioc->alt_ioc)
4203 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4204 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304206 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207
4208 /*
4209 * Reset flag that says we've enabled event notification
4210 */
4211 ioc->facts.EventState = 0;
4212
4213 if (ioc->alt_ioc)
4214 ioc->alt_ioc->facts.EventState = 0;
4215
4216 return hard_reset_done;
4217}
4218
4219/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004220/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221 * SendIocReset - Send IOCReset request to MPT adapter.
4222 * @ioc: Pointer to MPT_ADAPTER structure
4223 * @reset_type: reset type, expected values are
4224 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004225 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 *
4227 * Send IOCReset request to the MPT adapter.
4228 *
4229 * Returns 0 for success, non-zero for failure.
4230 */
4231static int
4232SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4233{
4234 int r;
4235 u32 state;
4236 int cntdn, count;
4237
Prakash, Sathya436ace72007-07-24 15:42:08 +05304238 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239 ioc->name, reset_type));
4240 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4241 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4242 return r;
4243
4244 /* FW ACK'd request, wait for READY state
4245 */
4246 count = 0;
4247 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4248
4249 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4250 cntdn--;
4251 count++;
4252 if (!cntdn) {
4253 if (sleepFlag != CAN_SLEEP)
4254 count *= 10;
4255
Kashyap, Desai2f187862009-05-29 16:52:37 +05304256 printk(MYIOC_s_ERR_FMT
4257 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
4258 ioc->name, state, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259 return -ETIME;
4260 }
4261
4262 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004263 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264 } else {
4265 mdelay (1); /* 1 msec delay */
4266 }
4267 }
4268
4269 /* TODO!
4270 * Cleanup all event stuff for this IOC; re-issue EventNotification
4271 * request if needed.
4272 */
4273 if (ioc->facts.Function)
4274 ioc->facts.EventState = 0;
4275
4276 return 0;
4277}
4278
4279/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004280/**
4281 * initChainBuffers - Allocate memory for and initialize chain buffers
4282 * @ioc: Pointer to MPT_ADAPTER structure
4283 *
4284 * Allocates memory for and initializes chain buffers,
4285 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286 */
4287static int
4288initChainBuffers(MPT_ADAPTER *ioc)
4289{
4290 u8 *mem;
4291 int sz, ii, num_chain;
4292 int scale, num_sge, numSGE;
4293
4294 /* ReqToChain size must equal the req_depth
4295 * index = req_idx
4296 */
4297 if (ioc->ReqToChain == NULL) {
4298 sz = ioc->req_depth * sizeof(int);
4299 mem = kmalloc(sz, GFP_ATOMIC);
4300 if (mem == NULL)
4301 return -1;
4302
4303 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304304 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 ioc->name, mem, sz));
4306 mem = kmalloc(sz, GFP_ATOMIC);
4307 if (mem == NULL)
4308 return -1;
4309
4310 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304311 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312 ioc->name, mem, sz));
4313 }
4314 for (ii = 0; ii < ioc->req_depth; ii++) {
4315 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4316 }
4317
4318 /* ChainToChain size must equal the total number
4319 * of chain buffers to be allocated.
4320 * index = chain_idx
4321 *
4322 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004323 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324 *
4325 * num_sge = num sge in request frame + last chain buffer
4326 * scale = num sge per chain buffer if no chain element
4327 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304328 scale = ioc->req_sz / ioc->SGE_size;
4329 if (ioc->sg_addr_size == sizeof(u64))
4330 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304332 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304334 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304336 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304338 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4339 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304341 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 ioc->name, num_sge, numSGE));
4343
Kashyap, Desai2f187862009-05-29 16:52:37 +05304344 if (ioc->bus_type == FC) {
4345 if (numSGE > MPT_SCSI_FC_SG_DEPTH)
4346 numSGE = MPT_SCSI_FC_SG_DEPTH;
4347 } else {
4348 if (numSGE > MPT_SCSI_SG_DEPTH)
4349 numSGE = MPT_SCSI_SG_DEPTH;
4350 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351
4352 num_chain = 1;
4353 while (numSGE - num_sge > 0) {
4354 num_chain++;
4355 num_sge += (scale - 1);
4356 }
4357 num_chain++;
4358
Prakash, Sathya436ace72007-07-24 15:42:08 +05304359 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360 ioc->name, numSGE, num_sge, num_chain));
4361
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004362 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363 num_chain *= MPT_SCSI_CAN_QUEUE;
4364 else
4365 num_chain *= MPT_FC_CAN_QUEUE;
4366
4367 ioc->num_chain = num_chain;
4368
4369 sz = num_chain * sizeof(int);
4370 if (ioc->ChainToChain == NULL) {
4371 mem = kmalloc(sz, GFP_ATOMIC);
4372 if (mem == NULL)
4373 return -1;
4374
4375 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304376 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 ioc->name, mem, sz));
4378 } else {
4379 mem = (u8 *) ioc->ChainToChain;
4380 }
4381 memset(mem, 0xFF, sz);
4382 return num_chain;
4383}
4384
4385/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004386/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4388 * @ioc: Pointer to MPT_ADAPTER structure
4389 *
4390 * This routine allocates memory for the MPT reply and request frame
4391 * pools (if necessary), and primes the IOC reply FIFO with
4392 * reply frames.
4393 *
4394 * Returns 0 for success, non-zero for failure.
4395 */
4396static int
4397PrimeIocFifos(MPT_ADAPTER *ioc)
4398{
4399 MPT_FRAME_HDR *mf;
4400 unsigned long flags;
4401 dma_addr_t alloc_dma;
4402 u8 *mem;
4403 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304404 u64 dma_mask;
4405
4406 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407
4408 /* Prime reply FIFO... */
4409
4410 if (ioc->reply_frames == NULL) {
4411 if ( (num_chain = initChainBuffers(ioc)) < 0)
4412 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304413 /*
4414 * 1078 errata workaround for the 36GB limitation
4415 */
4416 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
Andrew Morton8e20ce92009-06-18 16:49:17 -07004417 ioc->dma_mask > DMA_BIT_MASK(35)) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304418 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4419 && !pci_set_consistent_dma_mask(ioc->pcidev,
4420 DMA_BIT_MASK(32))) {
Andrew Morton8e20ce92009-06-18 16:49:17 -07004421 dma_mask = DMA_BIT_MASK(35);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304422 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4423 "setting 35 bit addressing for "
4424 "Request/Reply/Chain and Sense Buffers\n",
4425 ioc->name));
4426 } else {
4427 /*Reseting DMA mask to 64 bit*/
4428 pci_set_dma_mask(ioc->pcidev,
4429 DMA_BIT_MASK(64));
4430 pci_set_consistent_dma_mask(ioc->pcidev,
4431 DMA_BIT_MASK(64));
4432
4433 printk(MYIOC_s_ERR_FMT
4434 "failed setting 35 bit addressing for "
4435 "Request/Reply/Chain and Sense Buffers\n",
4436 ioc->name);
4437 return -1;
4438 }
4439 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440
4441 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304442 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304444 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445 ioc->name, reply_sz, reply_sz));
4446
4447 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304448 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304450 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 ioc->name, sz, sz));
4452 total_size += sz;
4453
4454 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304455 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304457 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 ioc->name, sz, sz, num_chain));
4459
4460 total_size += sz;
4461 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4462 if (mem == NULL) {
4463 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4464 ioc->name);
4465 goto out_fail;
4466 }
4467
Prakash, Sathya436ace72007-07-24 15:42:08 +05304468 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4470
4471 memset(mem, 0, total_size);
4472 ioc->alloc_total += total_size;
4473 ioc->alloc = mem;
4474 ioc->alloc_dma = alloc_dma;
4475 ioc->alloc_sz = total_size;
4476 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4477 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4478
Prakash, Sathya436ace72007-07-24 15:42:08 +05304479 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004480 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4481
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 alloc_dma += reply_sz;
4483 mem += reply_sz;
4484
4485 /* Request FIFO - WE manage this! */
4486
4487 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4488 ioc->req_frames_dma = alloc_dma;
4489
Prakash, Sathya436ace72007-07-24 15:42:08 +05304490 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 ioc->name, mem, (void *)(ulong)alloc_dma));
4492
4493 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4494
4495#if defined(CONFIG_MTRR) && 0
4496 /*
4497 * Enable Write Combining MTRR for IOC's memory region.
4498 * (at least as much as we can; "size and base must be
4499 * multiples of 4 kiB"
4500 */
4501 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4502 sz,
4503 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304504 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505 ioc->name, ioc->req_frames_dma, sz));
4506#endif
4507
4508 for (i = 0; i < ioc->req_depth; i++) {
4509 alloc_dma += ioc->req_sz;
4510 mem += ioc->req_sz;
4511 }
4512
4513 ioc->ChainBuffer = mem;
4514 ioc->ChainBufferDMA = alloc_dma;
4515
Prakash, Sathya436ace72007-07-24 15:42:08 +05304516 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4518
4519 /* Initialize the free chain Q.
4520 */
4521
4522 INIT_LIST_HEAD(&ioc->FreeChainQ);
4523
4524 /* Post the chain buffers to the FreeChainQ.
4525 */
4526 mem = (u8 *)ioc->ChainBuffer;
4527 for (i=0; i < num_chain; i++) {
4528 mf = (MPT_FRAME_HDR *) mem;
4529 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4530 mem += ioc->req_sz;
4531 }
4532
4533 /* Initialize Request frames linked list
4534 */
4535 alloc_dma = ioc->req_frames_dma;
4536 mem = (u8 *) ioc->req_frames;
4537
4538 spin_lock_irqsave(&ioc->FreeQlock, flags);
4539 INIT_LIST_HEAD(&ioc->FreeQ);
4540 for (i = 0; i < ioc->req_depth; i++) {
4541 mf = (MPT_FRAME_HDR *) mem;
4542
4543 /* Queue REQUESTs *internally*! */
4544 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4545
4546 mem += ioc->req_sz;
4547 }
4548 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4549
4550 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4551 ioc->sense_buf_pool =
4552 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4553 if (ioc->sense_buf_pool == NULL) {
4554 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4555 ioc->name);
4556 goto out_fail;
4557 }
4558
4559 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4560 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304561 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4563
4564 }
4565
4566 /* Post Reply frames to FIFO
4567 */
4568 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304569 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4571
4572 for (i = 0; i < ioc->reply_depth; i++) {
4573 /* Write each address to the IOC! */
4574 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4575 alloc_dma += ioc->reply_sz;
4576 }
4577
Andrew Morton8e20ce92009-06-18 16:49:17 -07004578 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304579 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4580 ioc->dma_mask))
4581 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4582 "restoring 64 bit addressing\n", ioc->name));
4583
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 return 0;
4585
4586out_fail:
Kashyap, Desai2f187862009-05-29 16:52:37 +05304587
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588 if (ioc->alloc != NULL) {
4589 sz = ioc->alloc_sz;
4590 pci_free_consistent(ioc->pcidev,
4591 sz,
4592 ioc->alloc, ioc->alloc_dma);
4593 ioc->reply_frames = NULL;
4594 ioc->req_frames = NULL;
4595 ioc->alloc_total -= sz;
4596 }
4597 if (ioc->sense_buf_pool != NULL) {
4598 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4599 pci_free_consistent(ioc->pcidev,
4600 sz,
4601 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4602 ioc->sense_buf_pool = NULL;
4603 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304604
Andrew Morton8e20ce92009-06-18 16:49:17 -07004605 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304606 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4607 DMA_BIT_MASK(64)))
4608 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4609 "restoring 64 bit addressing\n", ioc->name));
4610
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 return -1;
4612}
4613
4614/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4615/**
4616 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4617 * from IOC via doorbell handshake method.
4618 * @ioc: Pointer to MPT_ADAPTER structure
4619 * @reqBytes: Size of the request in bytes
4620 * @req: Pointer to MPT request frame
4621 * @replyBytes: Expected size of the reply in bytes
4622 * @u16reply: Pointer to area where reply should be written
4623 * @maxwait: Max wait time for a reply (in seconds)
4624 * @sleepFlag: Specifies whether the process can sleep
4625 *
4626 * NOTES: It is the callers responsibility to byte-swap fields in the
4627 * request which are greater than 1 byte in size. It is also the
4628 * callers responsibility to byte-swap response fields which are
4629 * greater than 1 byte in size.
4630 *
4631 * Returns 0 for success, non-zero for failure.
4632 */
4633static int
4634mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004635 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636{
4637 MPIDefaultReply_t *mptReply;
4638 int failcnt = 0;
4639 int t;
4640
4641 /*
4642 * Get ready to cache a handshake reply
4643 */
4644 ioc->hs_reply_idx = 0;
4645 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4646 mptReply->MsgLength = 0;
4647
4648 /*
4649 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4650 * then tell IOC that we want to handshake a request of N words.
4651 * (WRITE u32val to Doorbell reg).
4652 */
4653 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4654 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4655 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4656 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4657
4658 /*
4659 * Wait for IOC's doorbell handshake int
4660 */
4661 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4662 failcnt++;
4663
Prakash, Sathya436ace72007-07-24 15:42:08 +05304664 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4666
4667 /* Read doorbell and check for active bit */
4668 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4669 return -1;
4670
4671 /*
4672 * Clear doorbell int (WRITE 0 to IntStatus reg),
4673 * then wait for IOC to ACKnowledge that it's ready for
4674 * our handshake request.
4675 */
4676 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4677 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4678 failcnt++;
4679
4680 if (!failcnt) {
4681 int ii;
4682 u8 *req_as_bytes = (u8 *) req;
4683
4684 /*
4685 * Stuff request words via doorbell handshake,
4686 * with ACK from IOC for each.
4687 */
4688 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4689 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4690 (req_as_bytes[(ii*4) + 1] << 8) |
4691 (req_as_bytes[(ii*4) + 2] << 16) |
4692 (req_as_bytes[(ii*4) + 3] << 24));
4693
4694 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4695 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4696 failcnt++;
4697 }
4698
Prakash, Sathya436ace72007-07-24 15:42:08 +05304699 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004700 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701
Prakash, Sathya436ace72007-07-24 15:42:08 +05304702 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4704
4705 /*
4706 * Wait for completion of doorbell handshake reply from the IOC
4707 */
4708 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4709 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004710
Prakash, Sathya436ace72007-07-24 15:42:08 +05304711 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4713
4714 /*
4715 * Copy out the cached reply...
4716 */
4717 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4718 u16reply[ii] = ioc->hs_reply[ii];
4719 } else {
4720 return -99;
4721 }
4722
4723 return -failcnt;
4724}
4725
4726/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004727/**
4728 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729 * @ioc: Pointer to MPT_ADAPTER structure
4730 * @howlong: How long to wait (in seconds)
4731 * @sleepFlag: Specifies whether the process can sleep
4732 *
4733 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004734 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4735 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736 *
4737 * Returns a negative value on failure, else wait loop count.
4738 */
4739static int
4740WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4741{
4742 int cntdn;
4743 int count = 0;
4744 u32 intstat=0;
4745
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004746 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747
4748 if (sleepFlag == CAN_SLEEP) {
4749 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004750 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4752 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4753 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754 count++;
4755 }
4756 } else {
4757 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004758 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4760 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4761 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 count++;
4763 }
4764 }
4765
4766 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304767 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 ioc->name, count));
4769 return count;
4770 }
4771
4772 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4773 ioc->name, count, intstat);
4774 return -1;
4775}
4776
4777/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004778/**
4779 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780 * @ioc: Pointer to MPT_ADAPTER structure
4781 * @howlong: How long to wait (in seconds)
4782 * @sleepFlag: Specifies whether the process can sleep
4783 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004784 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4785 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786 *
4787 * Returns a negative value on failure, else wait loop count.
4788 */
4789static int
4790WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4791{
4792 int cntdn;
4793 int count = 0;
4794 u32 intstat=0;
4795
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004796 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 if (sleepFlag == CAN_SLEEP) {
4798 while (--cntdn) {
4799 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4800 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4801 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004802 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 count++;
4804 }
4805 } else {
4806 while (--cntdn) {
4807 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4808 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4809 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004810 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811 count++;
4812 }
4813 }
4814
4815 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304816 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817 ioc->name, count, howlong));
4818 return count;
4819 }
4820
4821 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4822 ioc->name, count, intstat);
4823 return -1;
4824}
4825
4826/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004827/**
4828 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829 * @ioc: Pointer to MPT_ADAPTER structure
4830 * @howlong: How long to wait (in seconds)
4831 * @sleepFlag: Specifies whether the process can sleep
4832 *
4833 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4834 * Reply is cached to IOC private area large enough to hold a maximum
4835 * of 128 bytes of reply data.
4836 *
4837 * Returns a negative value on failure, else size of reply in WORDS.
4838 */
4839static int
4840WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4841{
4842 int u16cnt = 0;
4843 int failcnt = 0;
4844 int t;
4845 u16 *hs_reply = ioc->hs_reply;
4846 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4847 u16 hword;
4848
4849 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4850
4851 /*
4852 * Get first two u16's so we can look at IOC's intended reply MsgLength
4853 */
4854 u16cnt=0;
4855 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4856 failcnt++;
4857 } else {
4858 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4859 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4860 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4861 failcnt++;
4862 else {
4863 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4864 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4865 }
4866 }
4867
Prakash, Sathya436ace72007-07-24 15:42:08 +05304868 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004869 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004870 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4871
4872 /*
4873 * If no error (and IOC said MsgLength is > 0), piece together
4874 * reply 16 bits at a time.
4875 */
4876 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4877 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4878 failcnt++;
4879 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4880 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004881 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882 hs_reply[u16cnt] = hword;
4883 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4884 }
4885
4886 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4887 failcnt++;
4888 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4889
4890 if (failcnt) {
4891 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4892 ioc->name);
4893 return -failcnt;
4894 }
4895#if 0
4896 else if (u16cnt != (2 * mptReply->MsgLength)) {
4897 return -101;
4898 }
4899 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4900 return -102;
4901 }
4902#endif
4903
Prakash, Sathya436ace72007-07-24 15:42:08 +05304904 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004905 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906
Prakash, Sathya436ace72007-07-24 15:42:08 +05304907 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908 ioc->name, t, u16cnt/2));
4909 return u16cnt/2;
4910}
4911
4912/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004913/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004914 * GetLanConfigPages - Fetch LANConfig pages.
4915 * @ioc: Pointer to MPT_ADAPTER structure
4916 *
4917 * Return: 0 for success
4918 * -ENOMEM if no memory available
4919 * -EPERM if not allowed due to ISR context
4920 * -EAGAIN if no msg frames currently available
4921 * -EFAULT for non-successful reply or no reply (timeout)
4922 */
4923static int
4924GetLanConfigPages(MPT_ADAPTER *ioc)
4925{
4926 ConfigPageHeader_t hdr;
4927 CONFIGPARMS cfg;
4928 LANPage0_t *ppage0_alloc;
4929 dma_addr_t page0_dma;
4930 LANPage1_t *ppage1_alloc;
4931 dma_addr_t page1_dma;
4932 int rc = 0;
4933 int data_sz;
4934 int copy_sz;
4935
4936 /* Get LAN Page 0 header */
4937 hdr.PageVersion = 0;
4938 hdr.PageLength = 0;
4939 hdr.PageNumber = 0;
4940 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004941 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942 cfg.physAddr = -1;
4943 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4944 cfg.dir = 0;
4945 cfg.pageAddr = 0;
4946 cfg.timeout = 0;
4947
4948 if ((rc = mpt_config(ioc, &cfg)) != 0)
4949 return rc;
4950
4951 if (hdr.PageLength > 0) {
4952 data_sz = hdr.PageLength * 4;
4953 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4954 rc = -ENOMEM;
4955 if (ppage0_alloc) {
4956 memset((u8 *)ppage0_alloc, 0, data_sz);
4957 cfg.physAddr = page0_dma;
4958 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4959
4960 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4961 /* save the data */
4962 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4963 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4964
4965 }
4966
4967 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4968
4969 /* FIXME!
4970 * Normalize endianness of structure data,
4971 * by byte-swapping all > 1 byte fields!
4972 */
4973
4974 }
4975
4976 if (rc)
4977 return rc;
4978 }
4979
4980 /* Get LAN Page 1 header */
4981 hdr.PageVersion = 0;
4982 hdr.PageLength = 0;
4983 hdr.PageNumber = 1;
4984 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004985 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986 cfg.physAddr = -1;
4987 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4988 cfg.dir = 0;
4989 cfg.pageAddr = 0;
4990
4991 if ((rc = mpt_config(ioc, &cfg)) != 0)
4992 return rc;
4993
4994 if (hdr.PageLength == 0)
4995 return 0;
4996
4997 data_sz = hdr.PageLength * 4;
4998 rc = -ENOMEM;
4999 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
5000 if (ppage1_alloc) {
5001 memset((u8 *)ppage1_alloc, 0, data_sz);
5002 cfg.physAddr = page1_dma;
5003 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5004
5005 if ((rc = mpt_config(ioc, &cfg)) == 0) {
5006 /* save the data */
5007 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
5008 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
5009 }
5010
5011 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
5012
5013 /* FIXME!
5014 * Normalize endianness of structure data,
5015 * by byte-swapping all > 1 byte fields!
5016 */
5017
5018 }
5019
5020 return rc;
5021}
5022
5023/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005024/**
5025 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005026 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005027 * @persist_opcode: see below
5028 *
5029 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
5030 * devices not currently present.
5031 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
5032 *
5033 * NOTE: Don't use not this function during interrupt time.
5034 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005035 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005036 */
5037
5038/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5039int
5040mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
5041{
5042 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
5043 SasIoUnitControlReply_t *sasIoUnitCntrReply;
5044 MPT_FRAME_HDR *mf = NULL;
5045 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305046 int ret = 0;
5047 unsigned long timeleft;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005048
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305049 mutex_lock(&ioc->mptbase_cmds.mutex);
5050
5051 /* init the internal cmd struct */
5052 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
5053 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005054
5055 /* insure garbage is not sent to fw */
5056 switch(persist_opcode) {
5057
5058 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
5059 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
5060 break;
5061
5062 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305063 ret = -1;
5064 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005065 }
5066
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305067 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
5068 __func__, persist_opcode);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005069
5070 /* Get a MF for this command.
5071 */
5072 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305073 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
5074 ret = -1;
5075 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005076 }
5077
5078 mpi_hdr = (MPIHeader_t *) mf;
5079 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
5080 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
5081 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
5082 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
5083 sasIoUnitCntrReq->Operation = persist_opcode;
5084
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005085 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305086 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
5087 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
5088 ret = -ETIME;
5089 printk(KERN_DEBUG "%s: failed\n", __func__);
5090 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
5091 goto out;
5092 if (!timeleft) {
5093 printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n",
5094 ioc->name, __func__);
5095 mpt_HardResetHandler(ioc, CAN_SLEEP);
5096 mpt_free_msg_frame(ioc, mf);
5097 }
5098 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005099 }
5100
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305101 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
5102 ret = -1;
5103 goto out;
5104 }
5105
5106 sasIoUnitCntrReply =
5107 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5108 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5109 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5110 __func__, sasIoUnitCntrReply->IOCStatus,
5111 sasIoUnitCntrReply->IOCLogInfo);
5112 printk(KERN_DEBUG "%s: failed\n", __func__);
5113 ret = -1;
5114 } else
5115 printk(KERN_DEBUG "%s: success\n", __func__);
5116 out:
5117
5118 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5119 mutex_unlock(&ioc->mptbase_cmds.mutex);
5120 return ret;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005121}
5122
5123/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005124
5125static void
5126mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5127 MpiEventDataRaid_t * pRaidEventData)
5128{
5129 int volume;
5130 int reason;
5131 int disk;
5132 int status;
5133 int flags;
5134 int state;
5135
5136 volume = pRaidEventData->VolumeID;
5137 reason = pRaidEventData->ReasonCode;
5138 disk = pRaidEventData->PhysDiskNum;
5139 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5140 flags = (status >> 0) & 0xff;
5141 state = (status >> 8) & 0xff;
5142
5143 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5144 return;
5145 }
5146
5147 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5148 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5149 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005150 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5151 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005152 } else {
5153 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5154 ioc->name, volume);
5155 }
5156
5157 switch(reason) {
5158 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5159 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5160 ioc->name);
5161 break;
5162
5163 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5164
5165 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5166 ioc->name);
5167 break;
5168
5169 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5170 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5171 ioc->name);
5172 break;
5173
5174 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5175 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5176 ioc->name,
5177 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5178 ? "optimal"
5179 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5180 ? "degraded"
5181 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5182 ? "failed"
5183 : "state unknown",
5184 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5185 ? ", enabled" : "",
5186 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5187 ? ", quiesced" : "",
5188 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5189 ? ", resync in progress" : "" );
5190 break;
5191
5192 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5193 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5194 ioc->name, disk);
5195 break;
5196
5197 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5198 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5199 ioc->name);
5200 break;
5201
5202 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5203 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5204 ioc->name);
5205 break;
5206
5207 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5208 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5209 ioc->name);
5210 break;
5211
5212 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5213 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5214 ioc->name,
5215 state == MPI_PHYSDISK0_STATUS_ONLINE
5216 ? "online"
5217 : state == MPI_PHYSDISK0_STATUS_MISSING
5218 ? "missing"
5219 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5220 ? "not compatible"
5221 : state == MPI_PHYSDISK0_STATUS_FAILED
5222 ? "failed"
5223 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5224 ? "initializing"
5225 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5226 ? "offline requested"
5227 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5228 ? "failed requested"
5229 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5230 ? "offline"
5231 : "state unknown",
5232 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5233 ? ", out of sync" : "",
5234 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5235 ? ", quiesced" : "" );
5236 break;
5237
5238 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5239 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5240 ioc->name, disk);
5241 break;
5242
5243 case MPI_EVENT_RAID_RC_SMART_DATA:
5244 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5245 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5246 break;
5247
5248 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5249 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5250 ioc->name, disk);
5251 break;
5252 }
5253}
5254
5255/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005256/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005257 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5258 * @ioc: Pointer to MPT_ADAPTER structure
5259 *
5260 * Returns: 0 for success
5261 * -ENOMEM if no memory available
5262 * -EPERM if not allowed due to ISR context
5263 * -EAGAIN if no msg frames currently available
5264 * -EFAULT for non-successful reply or no reply (timeout)
5265 */
5266static int
5267GetIoUnitPage2(MPT_ADAPTER *ioc)
5268{
5269 ConfigPageHeader_t hdr;
5270 CONFIGPARMS cfg;
5271 IOUnitPage2_t *ppage_alloc;
5272 dma_addr_t page_dma;
5273 int data_sz;
5274 int rc;
5275
5276 /* Get the page header */
5277 hdr.PageVersion = 0;
5278 hdr.PageLength = 0;
5279 hdr.PageNumber = 2;
5280 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005281 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005282 cfg.physAddr = -1;
5283 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5284 cfg.dir = 0;
5285 cfg.pageAddr = 0;
5286 cfg.timeout = 0;
5287
5288 if ((rc = mpt_config(ioc, &cfg)) != 0)
5289 return rc;
5290
5291 if (hdr.PageLength == 0)
5292 return 0;
5293
5294 /* Read the config page */
5295 data_sz = hdr.PageLength * 4;
5296 rc = -ENOMEM;
5297 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5298 if (ppage_alloc) {
5299 memset((u8 *)ppage_alloc, 0, data_sz);
5300 cfg.physAddr = page_dma;
5301 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5302
5303 /* If Good, save data */
5304 if ((rc = mpt_config(ioc, &cfg)) == 0)
5305 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5306
5307 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5308 }
5309
5310 return rc;
5311}
5312
5313/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005314/**
5315 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005316 * @ioc: Pointer to a Adapter Strucutre
5317 * @portnum: IOC port number
5318 *
5319 * Return: -EFAULT if read of config page header fails
5320 * or if no nvram
5321 * If read of SCSI Port Page 0 fails,
5322 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5323 * Adapter settings: async, narrow
5324 * Return 1
5325 * If read of SCSI Port Page 2 fails,
5326 * Adapter settings valid
5327 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5328 * Return 1
5329 * Else
5330 * Both valid
5331 * Return 0
5332 * CHECK - what type of locking mechanisms should be used????
5333 */
5334static int
5335mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5336{
5337 u8 *pbuf;
5338 dma_addr_t buf_dma;
5339 CONFIGPARMS cfg;
5340 ConfigPageHeader_t header;
5341 int ii;
5342 int data, rc = 0;
5343
5344 /* Allocate memory
5345 */
5346 if (!ioc->spi_data.nvram) {
5347 int sz;
5348 u8 *mem;
5349 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5350 mem = kmalloc(sz, GFP_ATOMIC);
5351 if (mem == NULL)
5352 return -EFAULT;
5353
5354 ioc->spi_data.nvram = (int *) mem;
5355
Prakash, Sathya436ace72007-07-24 15:42:08 +05305356 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005357 ioc->name, ioc->spi_data.nvram, sz));
5358 }
5359
5360 /* Invalidate NVRAM information
5361 */
5362 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5363 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5364 }
5365
5366 /* Read SPP0 header, allocate memory, then read page.
5367 */
5368 header.PageVersion = 0;
5369 header.PageLength = 0;
5370 header.PageNumber = 0;
5371 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005372 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005373 cfg.physAddr = -1;
5374 cfg.pageAddr = portnum;
5375 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5376 cfg.dir = 0;
5377 cfg.timeout = 0; /* use default */
5378 if (mpt_config(ioc, &cfg) != 0)
5379 return -EFAULT;
5380
5381 if (header.PageLength > 0) {
5382 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5383 if (pbuf) {
5384 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5385 cfg.physAddr = buf_dma;
5386 if (mpt_config(ioc, &cfg) != 0) {
5387 ioc->spi_data.maxBusWidth = MPT_NARROW;
5388 ioc->spi_data.maxSyncOffset = 0;
5389 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5390 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5391 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305392 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5393 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005394 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005395 } else {
5396 /* Save the Port Page 0 data
5397 */
5398 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5399 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5400 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5401
5402 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5403 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005404 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5405 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005406 ioc->name, pPP0->Capabilities));
5407 }
5408 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5409 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5410 if (data) {
5411 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5412 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5413 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305414 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5415 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005416 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005417 } else {
5418 ioc->spi_data.maxSyncOffset = 0;
5419 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5420 }
5421
5422 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5423
5424 /* Update the minSyncFactor based on bus type.
5425 */
5426 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5427 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5428
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005429 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005430 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305431 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5432 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005433 ioc->name, ioc->spi_data.minSyncFactor));
5434 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435 }
5436 }
5437 if (pbuf) {
5438 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5439 }
5440 }
5441 }
5442
5443 /* SCSI Port Page 2 - Read the header then the page.
5444 */
5445 header.PageVersion = 0;
5446 header.PageLength = 0;
5447 header.PageNumber = 2;
5448 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005449 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450 cfg.physAddr = -1;
5451 cfg.pageAddr = portnum;
5452 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5453 cfg.dir = 0;
5454 if (mpt_config(ioc, &cfg) != 0)
5455 return -EFAULT;
5456
5457 if (header.PageLength > 0) {
5458 /* Allocate memory and read SCSI Port Page 2
5459 */
5460 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5461 if (pbuf) {
5462 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5463 cfg.physAddr = buf_dma;
5464 if (mpt_config(ioc, &cfg) != 0) {
5465 /* Nvram data is left with INVALID mark
5466 */
5467 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005468 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5469
5470 /* This is an ATTO adapter, read Page2 accordingly
5471 */
5472 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5473 ATTODeviceInfo_t *pdevice = NULL;
5474 u16 ATTOFlags;
5475
5476 /* Save the Port Page 2 data
5477 * (reformat into a 32bit quantity)
5478 */
5479 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5480 pdevice = &pPP2->DeviceSettings[ii];
5481 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5482 data = 0;
5483
5484 /* Translate ATTO device flags to LSI format
5485 */
5486 if (ATTOFlags & ATTOFLAG_DISC)
5487 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5488 if (ATTOFlags & ATTOFLAG_ID_ENB)
5489 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5490 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5491 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5492 if (ATTOFlags & ATTOFLAG_TAGGED)
5493 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5494 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5495 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5496
5497 data = (data << 16) | (pdevice->Period << 8) | 10;
5498 ioc->spi_data.nvram[ii] = data;
5499 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500 } else {
5501 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5502 MpiDeviceInfo_t *pdevice = NULL;
5503
Moore, Ericd8e925d2006-01-16 18:53:06 -07005504 /*
5505 * Save "Set to Avoid SCSI Bus Resets" flag
5506 */
5507 ioc->spi_data.bus_reset =
5508 (le32_to_cpu(pPP2->PortFlags) &
5509 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5510 0 : 1 ;
5511
Linus Torvalds1da177e2005-04-16 15:20:36 -07005512 /* Save the Port Page 2 data
5513 * (reformat into a 32bit quantity)
5514 */
5515 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5516 ioc->spi_data.PortFlags = data;
5517 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5518 pdevice = &pPP2->DeviceSettings[ii];
5519 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5520 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5521 ioc->spi_data.nvram[ii] = data;
5522 }
5523 }
5524
5525 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5526 }
5527 }
5528
5529 /* Update Adapter limits with those from NVRAM
5530 * Comment: Don't need to do this. Target performance
5531 * parameters will never exceed the adapters limits.
5532 */
5533
5534 return rc;
5535}
5536
5537/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005538/**
5539 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005540 * @ioc: Pointer to a Adapter Strucutre
5541 * @portnum: IOC port number
5542 *
5543 * Return: -EFAULT if read of config page header fails
5544 * or 0 if success.
5545 */
5546static int
5547mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5548{
5549 CONFIGPARMS cfg;
5550 ConfigPageHeader_t header;
5551
5552 /* Read the SCSI Device Page 1 header
5553 */
5554 header.PageVersion = 0;
5555 header.PageLength = 0;
5556 header.PageNumber = 1;
5557 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005558 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 cfg.physAddr = -1;
5560 cfg.pageAddr = portnum;
5561 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5562 cfg.dir = 0;
5563 cfg.timeout = 0;
5564 if (mpt_config(ioc, &cfg) != 0)
5565 return -EFAULT;
5566
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005567 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5568 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569
5570 header.PageVersion = 0;
5571 header.PageLength = 0;
5572 header.PageNumber = 0;
5573 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5574 if (mpt_config(ioc, &cfg) != 0)
5575 return -EFAULT;
5576
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005577 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5578 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579
Prakash, Sathya436ace72007-07-24 15:42:08 +05305580 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5582
Prakash, Sathya436ace72007-07-24 15:42:08 +05305583 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5585 return 0;
5586}
5587
Eric Mooreb506ade2007-01-29 09:45:37 -07005588/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005589 * mpt_inactive_raid_list_free - This clears this link list.
5590 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005591 **/
5592static void
5593mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5594{
5595 struct inactive_raid_component_info *component_info, *pNext;
5596
5597 if (list_empty(&ioc->raid_data.inactive_list))
5598 return;
5599
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005600 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005601 list_for_each_entry_safe(component_info, pNext,
5602 &ioc->raid_data.inactive_list, list) {
5603 list_del(&component_info->list);
5604 kfree(component_info);
5605 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005606 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005607}
5608
5609/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005610 * 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 -07005611 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005612 * @ioc : pointer to per adapter structure
5613 * @channel : volume channel
5614 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005615 **/
5616static void
5617mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5618{
5619 CONFIGPARMS cfg;
5620 ConfigPageHeader_t hdr;
5621 dma_addr_t dma_handle;
5622 pRaidVolumePage0_t buffer = NULL;
5623 int i;
5624 RaidPhysDiskPage0_t phys_disk;
5625 struct inactive_raid_component_info *component_info;
5626 int handle_inactive_volumes;
5627
5628 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5629 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5630 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5631 cfg.pageAddr = (channel << 8) + id;
5632 cfg.cfghdr.hdr = &hdr;
5633 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5634
5635 if (mpt_config(ioc, &cfg) != 0)
5636 goto out;
5637
5638 if (!hdr.PageLength)
5639 goto out;
5640
5641 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5642 &dma_handle);
5643
5644 if (!buffer)
5645 goto out;
5646
5647 cfg.physAddr = dma_handle;
5648 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5649
5650 if (mpt_config(ioc, &cfg) != 0)
5651 goto out;
5652
5653 if (!buffer->NumPhysDisks)
5654 goto out;
5655
5656 handle_inactive_volumes =
5657 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5658 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5659 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5660 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5661
5662 if (!handle_inactive_volumes)
5663 goto out;
5664
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005665 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005666 for (i = 0; i < buffer->NumPhysDisks; i++) {
5667 if(mpt_raid_phys_disk_pg0(ioc,
5668 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5669 continue;
5670
5671 if ((component_info = kmalloc(sizeof (*component_info),
5672 GFP_KERNEL)) == NULL)
5673 continue;
5674
5675 component_info->volumeID = id;
5676 component_info->volumeBus = channel;
5677 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5678 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5679 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5680 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5681
5682 list_add_tail(&component_info->list,
5683 &ioc->raid_data.inactive_list);
5684 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005685 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005686
5687 out:
5688 if (buffer)
5689 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5690 dma_handle);
5691}
5692
5693/**
5694 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5695 * @ioc: Pointer to a Adapter Structure
5696 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5697 * @phys_disk: requested payload data returned
5698 *
5699 * Return:
5700 * 0 on success
5701 * -EFAULT if read of config page header fails or data pointer not NULL
5702 * -ENOMEM if pci_alloc failed
5703 **/
5704int
Kashyap, Desai2f187862009-05-29 16:52:37 +05305705mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
5706 RaidPhysDiskPage0_t *phys_disk)
Eric Mooreb506ade2007-01-29 09:45:37 -07005707{
Kashyap, Desai2f187862009-05-29 16:52:37 +05305708 CONFIGPARMS cfg;
5709 ConfigPageHeader_t hdr;
Eric Mooreb506ade2007-01-29 09:45:37 -07005710 dma_addr_t dma_handle;
5711 pRaidPhysDiskPage0_t buffer = NULL;
5712 int rc;
5713
5714 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5715 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
Kashyap, Desai2f187862009-05-29 16:52:37 +05305716 memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
Eric Mooreb506ade2007-01-29 09:45:37 -07005717
Kashyap, Desai2f187862009-05-29 16:52:37 +05305718 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
Eric Mooreb506ade2007-01-29 09:45:37 -07005719 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5720 cfg.cfghdr.hdr = &hdr;
5721 cfg.physAddr = -1;
5722 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5723
5724 if (mpt_config(ioc, &cfg) != 0) {
5725 rc = -EFAULT;
5726 goto out;
5727 }
5728
5729 if (!hdr.PageLength) {
5730 rc = -EFAULT;
5731 goto out;
5732 }
5733
5734 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5735 &dma_handle);
5736
5737 if (!buffer) {
5738 rc = -ENOMEM;
5739 goto out;
5740 }
5741
5742 cfg.physAddr = dma_handle;
5743 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5744 cfg.pageAddr = phys_disk_num;
5745
5746 if (mpt_config(ioc, &cfg) != 0) {
5747 rc = -EFAULT;
5748 goto out;
5749 }
5750
5751 rc = 0;
5752 memcpy(phys_disk, buffer, sizeof(*buffer));
5753 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5754
5755 out:
5756
5757 if (buffer)
5758 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5759 dma_handle);
5760
5761 return rc;
5762}
5763
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764/**
Kashyap, Desaia7938b02009-05-29 16:53:56 +05305765 * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
5766 * @ioc: Pointer to a Adapter Structure
5767 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5768 *
5769 * Return:
5770 * returns number paths
5771 **/
5772int
5773mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
5774{
5775 CONFIGPARMS cfg;
5776 ConfigPageHeader_t hdr;
5777 dma_addr_t dma_handle;
5778 pRaidPhysDiskPage1_t buffer = NULL;
5779 int rc;
5780
5781 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5782 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5783
5784 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5785 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5786 hdr.PageNumber = 1;
5787 cfg.cfghdr.hdr = &hdr;
5788 cfg.physAddr = -1;
5789 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5790
5791 if (mpt_config(ioc, &cfg) != 0) {
5792 rc = 0;
5793 goto out;
5794 }
5795
5796 if (!hdr.PageLength) {
5797 rc = 0;
5798 goto out;
5799 }
5800
5801 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5802 &dma_handle);
5803
5804 if (!buffer) {
5805 rc = 0;
5806 goto out;
5807 }
5808
5809 cfg.physAddr = dma_handle;
5810 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5811 cfg.pageAddr = phys_disk_num;
5812
5813 if (mpt_config(ioc, &cfg) != 0) {
5814 rc = 0;
5815 goto out;
5816 }
5817
5818 rc = buffer->NumPhysDiskPaths;
5819 out:
5820
5821 if (buffer)
5822 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5823 dma_handle);
5824
5825 return rc;
5826}
5827EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
5828
5829/**
5830 * mpt_raid_phys_disk_pg1 - returns phys disk page 1
5831 * @ioc: Pointer to a Adapter Structure
5832 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5833 * @phys_disk: requested payload data returned
5834 *
5835 * Return:
5836 * 0 on success
5837 * -EFAULT if read of config page header fails or data pointer not NULL
5838 * -ENOMEM if pci_alloc failed
5839 **/
5840int
5841mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
5842 RaidPhysDiskPage1_t *phys_disk)
5843{
5844 CONFIGPARMS cfg;
5845 ConfigPageHeader_t hdr;
5846 dma_addr_t dma_handle;
5847 pRaidPhysDiskPage1_t buffer = NULL;
5848 int rc;
5849 int i;
5850 __le64 sas_address;
5851
5852 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5853 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5854 rc = 0;
5855
5856 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5857 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5858 hdr.PageNumber = 1;
5859 cfg.cfghdr.hdr = &hdr;
5860 cfg.physAddr = -1;
5861 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5862
5863 if (mpt_config(ioc, &cfg) != 0) {
5864 rc = -EFAULT;
5865 goto out;
5866 }
5867
5868 if (!hdr.PageLength) {
5869 rc = -EFAULT;
5870 goto out;
5871 }
5872
5873 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5874 &dma_handle);
5875
5876 if (!buffer) {
5877 rc = -ENOMEM;
5878 goto out;
5879 }
5880
5881 cfg.physAddr = dma_handle;
5882 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5883 cfg.pageAddr = phys_disk_num;
5884
5885 if (mpt_config(ioc, &cfg) != 0) {
5886 rc = -EFAULT;
5887 goto out;
5888 }
5889
5890 phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
5891 phys_disk->PhysDiskNum = phys_disk_num;
5892 for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
5893 phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
5894 phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
5895 phys_disk->Path[i].OwnerIdentifier =
5896 buffer->Path[i].OwnerIdentifier;
5897 phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
5898 memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
5899 sas_address = le64_to_cpu(sas_address);
5900 memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
5901 memcpy(&sas_address,
5902 &buffer->Path[i].OwnerWWID, sizeof(__le64));
5903 sas_address = le64_to_cpu(sas_address);
5904 memcpy(&phys_disk->Path[i].OwnerWWID,
5905 &sas_address, sizeof(__le64));
5906 }
5907
5908 out:
5909
5910 if (buffer)
5911 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5912 dma_handle);
5913
5914 return rc;
5915}
5916EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
5917
5918
5919/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005920 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5921 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005922 *
5923 * Return:
5924 * 0 on success
5925 * -EFAULT if read of config page header fails or data pointer not NULL
5926 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005927 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005928int
5929mpt_findImVolumes(MPT_ADAPTER *ioc)
5930{
5931 IOCPage2_t *pIoc2;
5932 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005933 dma_addr_t ioc2_dma;
5934 CONFIGPARMS cfg;
5935 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005936 int rc = 0;
5937 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005938 int i;
5939
5940 if (!ioc->ir_firmware)
5941 return 0;
5942
5943 /* Free the old page
5944 */
5945 kfree(ioc->raid_data.pIocPg2);
5946 ioc->raid_data.pIocPg2 = NULL;
5947 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005948
5949 /* Read IOCP2 header then the page.
5950 */
5951 header.PageVersion = 0;
5952 header.PageLength = 0;
5953 header.PageNumber = 2;
5954 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005955 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005956 cfg.physAddr = -1;
5957 cfg.pageAddr = 0;
5958 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5959 cfg.dir = 0;
5960 cfg.timeout = 0;
5961 if (mpt_config(ioc, &cfg) != 0)
5962 return -EFAULT;
5963
5964 if (header.PageLength == 0)
5965 return -EFAULT;
5966
5967 iocpage2sz = header.PageLength * 4;
5968 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5969 if (!pIoc2)
5970 return -ENOMEM;
5971
5972 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5973 cfg.physAddr = ioc2_dma;
5974 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005975 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005976
Eric Mooreb506ade2007-01-29 09:45:37 -07005977 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5978 if (!mem)
5979 goto out;
5980
Linus Torvalds1da177e2005-04-16 15:20:36 -07005981 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005982 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005983
Eric Mooreb506ade2007-01-29 09:45:37 -07005984 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005985
Eric Mooreb506ade2007-01-29 09:45:37 -07005986 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5987 mpt_inactive_raid_volumes(ioc,
5988 pIoc2->RaidVolume[i].VolumeBus,
5989 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990
Eric Mooreb506ade2007-01-29 09:45:37 -07005991 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5993
5994 return rc;
5995}
5996
Moore, Ericc972c702006-03-14 09:14:06 -07005997static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005998mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5999{
6000 IOCPage3_t *pIoc3;
6001 u8 *mem;
6002 CONFIGPARMS cfg;
6003 ConfigPageHeader_t header;
6004 dma_addr_t ioc3_dma;
6005 int iocpage3sz = 0;
6006
6007 /* Free the old page
6008 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006009 kfree(ioc->raid_data.pIocPg3);
6010 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006011
6012 /* There is at least one physical disk.
6013 * Read and save IOC Page 3
6014 */
6015 header.PageVersion = 0;
6016 header.PageLength = 0;
6017 header.PageNumber = 3;
6018 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006019 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006020 cfg.physAddr = -1;
6021 cfg.pageAddr = 0;
6022 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6023 cfg.dir = 0;
6024 cfg.timeout = 0;
6025 if (mpt_config(ioc, &cfg) != 0)
6026 return 0;
6027
6028 if (header.PageLength == 0)
6029 return 0;
6030
6031 /* Read Header good, alloc memory
6032 */
6033 iocpage3sz = header.PageLength * 4;
6034 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
6035 if (!pIoc3)
6036 return 0;
6037
6038 /* Read the Page and save the data
6039 * into malloc'd memory.
6040 */
6041 cfg.physAddr = ioc3_dma;
6042 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6043 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07006044 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045 if (mem) {
6046 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006047 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006048 }
6049 }
6050
6051 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
6052
6053 return 0;
6054}
6055
6056static void
6057mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
6058{
6059 IOCPage4_t *pIoc4;
6060 CONFIGPARMS cfg;
6061 ConfigPageHeader_t header;
6062 dma_addr_t ioc4_dma;
6063 int iocpage4sz;
6064
6065 /* Read and save IOC Page 4
6066 */
6067 header.PageVersion = 0;
6068 header.PageLength = 0;
6069 header.PageNumber = 4;
6070 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006071 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072 cfg.physAddr = -1;
6073 cfg.pageAddr = 0;
6074 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6075 cfg.dir = 0;
6076 cfg.timeout = 0;
6077 if (mpt_config(ioc, &cfg) != 0)
6078 return;
6079
6080 if (header.PageLength == 0)
6081 return;
6082
6083 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
6084 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
6085 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
6086 if (!pIoc4)
6087 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06006088 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006089 } else {
6090 ioc4_dma = ioc->spi_data.IocPg4_dma;
6091 iocpage4sz = ioc->spi_data.IocPg4Sz;
6092 }
6093
6094 /* Read the Page into dma memory.
6095 */
6096 cfg.physAddr = ioc4_dma;
6097 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6098 if (mpt_config(ioc, &cfg) == 0) {
6099 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
6100 ioc->spi_data.IocPg4_dma = ioc4_dma;
6101 ioc->spi_data.IocPg4Sz = iocpage4sz;
6102 } else {
6103 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
6104 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06006105 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006106 }
6107}
6108
6109static void
6110mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
6111{
6112 IOCPage1_t *pIoc1;
6113 CONFIGPARMS cfg;
6114 ConfigPageHeader_t header;
6115 dma_addr_t ioc1_dma;
6116 int iocpage1sz = 0;
6117 u32 tmp;
6118
6119 /* Check the Coalescing Timeout in IOC Page 1
6120 */
6121 header.PageVersion = 0;
6122 header.PageLength = 0;
6123 header.PageNumber = 1;
6124 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006125 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006126 cfg.physAddr = -1;
6127 cfg.pageAddr = 0;
6128 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6129 cfg.dir = 0;
6130 cfg.timeout = 0;
6131 if (mpt_config(ioc, &cfg) != 0)
6132 return;
6133
6134 if (header.PageLength == 0)
6135 return;
6136
6137 /* Read Header good, alloc memory
6138 */
6139 iocpage1sz = header.PageLength * 4;
6140 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
6141 if (!pIoc1)
6142 return;
6143
6144 /* Read the Page and check coalescing timeout
6145 */
6146 cfg.physAddr = ioc1_dma;
6147 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6148 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306149
Linus Torvalds1da177e2005-04-16 15:20:36 -07006150 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
6151 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
6152 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
6153
Prakash, Sathya436ace72007-07-24 15:42:08 +05306154 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006155 ioc->name, tmp));
6156
6157 if (tmp > MPT_COALESCING_TIMEOUT) {
6158 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
6159
6160 /* Write NVRAM and current
6161 */
6162 cfg.dir = 1;
6163 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
6164 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306165 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006166 ioc->name, MPT_COALESCING_TIMEOUT));
6167
6168 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
6169 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306170 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6171 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006172 ioc->name, MPT_COALESCING_TIMEOUT));
6173 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306174 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6175 "Reset NVRAM Coalescing Timeout Failed\n",
6176 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006177 }
6178
6179 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306180 dprintk(ioc, printk(MYIOC_s_WARN_FMT
6181 "Reset of Current Coalescing Timeout Failed!\n",
6182 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006183 }
6184 }
6185
6186 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306187 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006188 }
6189 }
6190
6191 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
6192
6193 return;
6194}
6195
Prakash, Sathyaedb90682007-07-17 14:39:14 +05306196static void
6197mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
6198{
6199 CONFIGPARMS cfg;
6200 ConfigPageHeader_t hdr;
6201 dma_addr_t buf_dma;
6202 ManufacturingPage0_t *pbuf = NULL;
6203
6204 memset(&cfg, 0 , sizeof(CONFIGPARMS));
6205 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
6206
6207 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
6208 cfg.cfghdr.hdr = &hdr;
6209 cfg.physAddr = -1;
6210 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6211 cfg.timeout = 10;
6212
6213 if (mpt_config(ioc, &cfg) != 0)
6214 goto out;
6215
6216 if (!cfg.cfghdr.hdr->PageLength)
6217 goto out;
6218
6219 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6220 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
6221 if (!pbuf)
6222 goto out;
6223
6224 cfg.physAddr = buf_dma;
6225
6226 if (mpt_config(ioc, &cfg) != 0)
6227 goto out;
6228
6229 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
6230 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
6231 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
6232
6233 out:
6234
6235 if (pbuf)
6236 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
6237}
6238
Linus Torvalds1da177e2005-04-16 15:20:36 -07006239/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006240/**
6241 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006242 * @ioc: Pointer to MPT_ADAPTER structure
6243 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05306244 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07006245 */
6246static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05306247SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006248{
Kashyap, Desaifd761752009-05-29 16:39:06 +05306249 EventNotification_t evn;
6250 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251
Kashyap, Desaifd761752009-05-29 16:39:06 +05306252 memset(&evn, 0, sizeof(EventNotification_t));
6253 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006254
Kashyap, Desaifd761752009-05-29 16:39:06 +05306255 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
6256 evn.Switch = EvSwitch;
6257 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006258
Kashyap, Desaifd761752009-05-29 16:39:06 +05306259 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6260 "Sending EventNotification (%d) request %p\n",
6261 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006262
Kashyap, Desaifd761752009-05-29 16:39:06 +05306263 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6264 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6265 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006266}
6267
6268/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6269/**
6270 * SendEventAck - Send EventAck request to MPT adapter.
6271 * @ioc: Pointer to MPT_ADAPTER structure
6272 * @evnp: Pointer to original EventNotification request
6273 */
6274static int
6275SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6276{
6277 EventAck_t *pAck;
6278
6279 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306280 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306281 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006282 return -1;
6283 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006284
Prakash, Sathya436ace72007-07-24 15:42:08 +05306285 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006286
6287 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6288 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006289 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006290 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006291 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006292 pAck->Event = evnp->Event;
6293 pAck->EventContext = evnp->EventContext;
6294
6295 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6296
6297 return 0;
6298}
6299
6300/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6301/**
6302 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006303 * @ioc: Pointer to an adapter structure
6304 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006305 * action, page address, direction, physical address
6306 * and pointer to a configuration page header
6307 * Page header is updated.
6308 *
6309 * Returns 0 for success
6310 * -EPERM if not allowed due to ISR context
6311 * -EAGAIN if no msg frames currently available
6312 * -EFAULT for non-successful reply or no reply (timeout)
6313 */
6314int
6315mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6316{
6317 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306318 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006319 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006320 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306321 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006322 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306323 long timeout;
6324 int ret;
6325 u8 page_type = 0, extend_page;
6326 unsigned long timeleft;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306327 unsigned long flags;
6328 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306329 u8 issue_hard_reset = 0;
6330 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006331
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006332 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006333 * to be in ISR context, because that is fatal!
6334 */
6335 in_isr = in_interrupt();
6336 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306337 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338 ioc->name));
6339 return -EPERM;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306340 }
6341
6342 /* don't send a config page during diag reset */
6343 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6344 if (ioc->ioc_reset_in_progress) {
6345 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6346 "%s: busy with host reset\n", ioc->name, __func__));
6347 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6348 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006349 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306350 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006351
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306352 /* don't send if no chance of success */
6353 if (!ioc->active ||
6354 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6355 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6356 "%s: ioc not operational, %d, %xh\n",
6357 ioc->name, __func__, ioc->active,
6358 mpt_GetIocState(ioc, 0)));
6359 return -EFAULT;
6360 }
6361
6362 retry_config:
6363 mutex_lock(&ioc->mptbase_cmds.mutex);
6364 /* init the internal cmd struct */
6365 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6366 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6367
Linus Torvalds1da177e2005-04-16 15:20:36 -07006368 /* Get and Populate a free Frame
6369 */
6370 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306371 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6372 "mpt_config: no msg frames!\n", ioc->name));
6373 ret = -EAGAIN;
6374 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006375 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306376
Linus Torvalds1da177e2005-04-16 15:20:36 -07006377 pReq = (Config_t *)mf;
6378 pReq->Action = pCfg->action;
6379 pReq->Reserved = 0;
6380 pReq->ChainOffset = 0;
6381 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006382
6383 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006384 pReq->ExtPageLength = 0;
6385 pReq->ExtPageType = 0;
6386 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006387
Linus Torvalds1da177e2005-04-16 15:20:36 -07006388 for (ii=0; ii < 8; ii++)
6389 pReq->Reserved2[ii] = 0;
6390
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006391 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6392 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6393 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6394 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6395
6396 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6397 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6398 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6399 pReq->ExtPageType = pExtHdr->ExtPageType;
6400 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6401
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306402 /* Page Length must be treated as a reserved field for the
6403 * extended header.
6404 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006405 pReq->Header.PageLength = 0;
6406 }
6407
Linus Torvalds1da177e2005-04-16 15:20:36 -07006408 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6409
6410 /* Add a SGE to the config request.
6411 */
6412 if (pCfg->dir)
6413 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6414 else
6415 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6416
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306417 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6418 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006419 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306420 page_type = pReq->ExtPageType;
6421 extend_page = 1;
6422 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006423 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306424 page_type = pReq->Header.PageType;
6425 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006426 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006427
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306428 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6429 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6430 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6431
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306432 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306433 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006434 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306435 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6436 timeout);
6437 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6438 ret = -ETIME;
6439 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6440 "Failed Sending Config request type 0x%x, page 0x%x,"
6441 " action %d, status %xh, time left %ld\n\n",
6442 ioc->name, page_type, pReq->Header.PageNumber,
6443 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6444 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6445 goto out;
6446 if (!timeleft)
6447 issue_hard_reset = 1;
6448 goto out;
6449 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006450
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306451 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6452 ret = -1;
6453 goto out;
6454 }
6455 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6456 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6457 if (ret == MPI_IOCSTATUS_SUCCESS) {
6458 if (extend_page) {
6459 pCfg->cfghdr.ehdr->ExtPageLength =
6460 le16_to_cpu(pReply->ExtPageLength);
6461 pCfg->cfghdr.ehdr->ExtPageType =
6462 pReply->ExtPageType;
6463 }
6464 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6465 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6466 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6467 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006468
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306469 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006470
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306471 if (retry_count)
6472 printk(MYIOC_s_INFO_FMT "Retry completed "
6473 "ret=0x%x timeleft=%ld\n",
6474 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006475
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306476 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6477 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006478
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306479out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006480
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306481 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6482 mutex_unlock(&ioc->mptbase_cmds.mutex);
6483 if (issue_hard_reset) {
6484 issue_hard_reset = 0;
6485 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
6486 ioc->name, __func__);
6487 mpt_HardResetHandler(ioc, CAN_SLEEP);
6488 mpt_free_msg_frame(ioc, mf);
6489 /* attempt one retry for a timed out command */
6490 if (!retry_count) {
6491 printk(MYIOC_s_INFO_FMT
6492 "Attempting Retry Config request"
6493 " type 0x%x, page 0x%x,"
6494 " action %d\n", ioc->name, page_type,
6495 pCfg->cfghdr.hdr->PageNumber, pCfg->action);
6496 retry_count++;
6497 goto retry_config;
6498 }
6499 }
6500 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006501
Linus Torvalds1da177e2005-04-16 15:20:36 -07006502}
6503
6504/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006505/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006506 * mpt_ioc_reset - Base cleanup for hard reset
6507 * @ioc: Pointer to the adapter structure
6508 * @reset_phase: Indicates pre- or post-reset functionality
6509 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006510 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006511 */
6512static int
6513mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6514{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306515 switch (reset_phase) {
6516 case MPT_IOC_SETUP_RESET:
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306517 ioc->taskmgmt_quiesce_io = 1;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306518 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6519 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
6520 break;
6521 case MPT_IOC_PRE_RESET:
6522 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6523 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
6524 break;
6525 case MPT_IOC_POST_RESET:
6526 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6527 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
6528/* wake up mptbase_cmds */
6529 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6530 ioc->mptbase_cmds.status |=
6531 MPT_MGMT_STATUS_DID_IOCRESET;
6532 complete(&ioc->mptbase_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006533 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306534/* wake up taskmgmt_cmds */
6535 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
6536 ioc->taskmgmt_cmds.status |=
6537 MPT_MGMT_STATUS_DID_IOCRESET;
6538 complete(&ioc->taskmgmt_cmds.done);
6539 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306540 break;
6541 default:
6542 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006543 }
6544
6545 return 1; /* currently means nothing really */
6546}
6547
6548
6549#ifdef CONFIG_PROC_FS /* { */
6550/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6551/*
6552 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6553 */
6554/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006555/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006556 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6557 *
6558 * Returns 0 for success, non-zero for failure.
6559 */
6560static int
6561procmpt_create(void)
6562{
6563 struct proc_dir_entry *ent;
6564
6565 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6566 if (mpt_proc_root_dir == NULL)
6567 return -ENOTDIR;
6568
6569 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6570 if (ent)
6571 ent->read_proc = procmpt_summary_read;
6572
6573 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6574 if (ent)
6575 ent->read_proc = procmpt_version_read;
6576
6577 return 0;
6578}
6579
6580/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006581/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006582 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6583 *
6584 * Returns 0 for success, non-zero for failure.
6585 */
6586static void
6587procmpt_destroy(void)
6588{
6589 remove_proc_entry("version", mpt_proc_root_dir);
6590 remove_proc_entry("summary", mpt_proc_root_dir);
6591 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6592}
6593
6594/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006595/**
6596 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006597 * @buf: Pointer to area to write information
6598 * @start: Pointer to start pointer
6599 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006600 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006601 * @eof: Pointer to EOF integer
6602 * @data: Pointer
6603 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006604 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006605 * Returns number of characters written to process performing the read.
6606 */
6607static int
6608procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6609{
6610 MPT_ADAPTER *ioc;
6611 char *out = buf;
6612 int len;
6613
6614 if (data) {
6615 int more = 0;
6616
6617 ioc = data;
6618 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6619
6620 out += more;
6621 } else {
6622 list_for_each_entry(ioc, &ioc_list, list) {
6623 int more = 0;
6624
6625 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6626
6627 out += more;
6628 if ((out-buf) >= request)
6629 break;
6630 }
6631 }
6632
6633 len = out - buf;
6634
6635 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6636}
6637
6638/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006639/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006640 * procmpt_version_read - Handle read request from /proc/mpt/version.
6641 * @buf: Pointer to area to write information
6642 * @start: Pointer to start pointer
6643 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006644 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006645 * @eof: Pointer to EOF integer
6646 * @data: Pointer
6647 *
6648 * Returns number of characters written to process performing the read.
6649 */
6650static int
6651procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6652{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306653 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006654 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006655 char *drvname;
6656 int len;
6657
6658 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6659 len += sprintf(buf+len, " Fusion MPT base driver\n");
6660
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006661 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006662 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006663 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306664 if (MptCallbacks[cb_idx]) {
6665 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006666 case MPTSPI_DRIVER:
6667 if (!scsi++) drvname = "SPI host";
6668 break;
6669 case MPTFC_DRIVER:
6670 if (!fc++) drvname = "FC host";
6671 break;
6672 case MPTSAS_DRIVER:
6673 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006674 break;
6675 case MPTLAN_DRIVER:
6676 if (!lan++) drvname = "LAN";
6677 break;
6678 case MPTSTM_DRIVER:
6679 if (!targ++) drvname = "SCSI target";
6680 break;
6681 case MPTCTL_DRIVER:
6682 if (!ctl++) drvname = "ioctl";
6683 break;
6684 }
6685
6686 if (drvname)
6687 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6688 }
6689 }
6690
6691 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6692}
6693
6694/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006695/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006696 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6697 * @buf: Pointer to area to write information
6698 * @start: Pointer to start pointer
6699 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006700 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006701 * @eof: Pointer to EOF integer
6702 * @data: Pointer
6703 *
6704 * Returns number of characters written to process performing the read.
6705 */
6706static int
6707procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6708{
6709 MPT_ADAPTER *ioc = data;
6710 int len;
6711 char expVer[32];
6712 int sz;
6713 int p;
6714
6715 mpt_get_fw_exp_ver(expVer, ioc);
6716
6717 len = sprintf(buf, "%s:", ioc->name);
6718 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6719 len += sprintf(buf+len, " (f/w download boot flag set)");
6720// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6721// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6722
6723 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6724 ioc->facts.ProductID,
6725 ioc->prod_name);
6726 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6727 if (ioc->facts.FWImageSize)
6728 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6729 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6730 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6731 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6732
6733 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6734 ioc->facts.CurrentHostMfaHighAddr);
6735 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6736 ioc->facts.CurrentSenseBufferHighAddr);
6737
6738 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6739 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6740
6741 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6742 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6743 /*
6744 * Rounding UP to nearest 4-kB boundary here...
6745 */
6746 sz = (ioc->req_sz * ioc->req_depth) + 128;
6747 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6748 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6749 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6750 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6751 4*ioc->facts.RequestFrameSize,
6752 ioc->facts.GlobalCredits);
6753
6754 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6755 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6756 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6757 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6758 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6759 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6760 ioc->facts.CurReplyFrameSize,
6761 ioc->facts.ReplyQueueDepth);
6762
6763 len += sprintf(buf+len, " MaxDevices = %d\n",
6764 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6765 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6766
6767 /* per-port info */
6768 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6769 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6770 p+1,
6771 ioc->facts.NumberOfPorts);
6772 if (ioc->bus_type == FC) {
6773 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6774 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6775 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6776 a[5], a[4], a[3], a[2], a[1], a[0]);
6777 }
6778 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6779 ioc->fc_port_page0[p].WWNN.High,
6780 ioc->fc_port_page0[p].WWNN.Low,
6781 ioc->fc_port_page0[p].WWPN.High,
6782 ioc->fc_port_page0[p].WWPN.Low);
6783 }
6784 }
6785
6786 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6787}
6788
6789#endif /* CONFIG_PROC_FS } */
6790
6791/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6792static void
6793mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6794{
6795 buf[0] ='\0';
6796 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6797 sprintf(buf, " (Exp %02d%02d)",
6798 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6799 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6800
6801 /* insider hack! */
6802 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6803 strcat(buf, " [MDBG]");
6804 }
6805}
6806
6807/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6808/**
6809 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6810 * @ioc: Pointer to MPT_ADAPTER structure
6811 * @buffer: Pointer to buffer where IOC summary info should be written
6812 * @size: Pointer to number of bytes we wrote (set by this routine)
6813 * @len: Offset at which to start writing in buffer
6814 * @showlan: Display LAN stuff?
6815 *
6816 * This routine writes (english readable) ASCII text, which represents
6817 * a summary of IOC information, to a buffer.
6818 */
6819void
6820mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6821{
6822 char expVer[32];
6823 int y;
6824
6825 mpt_get_fw_exp_ver(expVer, ioc);
6826
6827 /*
6828 * Shorter summary of attached ioc's...
6829 */
6830 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6831 ioc->name,
6832 ioc->prod_name,
6833 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6834 ioc->facts.FWVersion.Word,
6835 expVer,
6836 ioc->facts.NumberOfPorts,
6837 ioc->req_depth);
6838
6839 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6840 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6841 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6842 a[5], a[4], a[3], a[2], a[1], a[0]);
6843 }
6844
Linus Torvalds1da177e2005-04-16 15:20:36 -07006845 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006846
6847 if (!ioc->active)
6848 y += sprintf(buffer+len+y, " (disabled)");
6849
6850 y += sprintf(buffer+len+y, "\n");
6851
6852 *size = y;
6853}
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306854/**
6855 * mpt_set_taskmgmt_in_progress_flag - set flags associated with task managment
6856 * @ioc: Pointer to MPT_ADAPTER structure
6857 *
6858 * Returns 0 for SUCCESS or -1 if FAILED.
6859 *
6860 * If -1 is return, then it was not possible to set the flags
6861 **/
6862int
6863mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6864{
6865 unsigned long flags;
6866 int retval;
6867
6868 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6869 if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
6870 (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
6871 retval = -1;
6872 goto out;
6873 }
6874 retval = 0;
6875 ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306876 ioc->taskmgmt_quiesce_io = 1;
6877 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306878 ioc->alt_ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306879 ioc->alt_ioc->taskmgmt_quiesce_io = 1;
6880 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306881 out:
6882 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6883 return retval;
6884}
6885EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
6886
6887/**
6888 * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task managment
6889 * @ioc: Pointer to MPT_ADAPTER structure
6890 *
6891 **/
6892void
6893mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6894{
6895 unsigned long flags;
6896
6897 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6898 ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306899 ioc->taskmgmt_quiesce_io = 0;
6900 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306901 ioc->alt_ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306902 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
6903 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306904 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6905}
6906EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006907
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306908
6909/**
6910 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6911 * the kernel
6912 * @ioc: Pointer to MPT_ADAPTER structure
6913 *
6914 **/
6915void
6916mpt_halt_firmware(MPT_ADAPTER *ioc)
6917{
6918 u32 ioc_raw_state;
6919
6920 ioc_raw_state = mpt_GetIocState(ioc, 0);
6921
6922 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6923 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6924 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6925 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6926 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6927 } else {
6928 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6929 panic("%s: Firmware is halted due to command timeout\n",
6930 ioc->name);
6931 }
6932}
6933EXPORT_SYMBOL(mpt_halt_firmware);
6934
Linus Torvalds1da177e2005-04-16 15:20:36 -07006935/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6936/*
6937 * Reset Handling
6938 */
6939/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6940/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006941 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006942 * @ioc: Pointer to MPT_ADAPTER structure
6943 * @sleepFlag: Indicates if sleep or schedule must be called.
6944 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006945 * Issues SCSI Task Management call based on input arg values.
6946 * If TaskMgmt fails, returns associated SCSI request.
6947 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006948 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6949 * or a non-interrupt thread. In the former, must not call schedule().
6950 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006951 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006952 * FW reload/initialization failed.
6953 *
6954 * Returns 0 for SUCCESS or -1 if FAILED.
6955 */
6956int
6957mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6958{
6959 int rc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306960 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006961 unsigned long flags;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306962 unsigned long time_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006963
Prakash, Sathya436ace72007-07-24 15:42:08 +05306964 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006965#ifdef MFCNT
6966 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6967 printk("MF count 0x%x !\n", ioc->mfcnt);
6968#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306969 if (mpt_fwfault_debug)
6970 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006971
6972 /* Reset the adapter. Prevent more than 1 call to
6973 * mpt_do_ioc_recovery at any instant in time.
6974 */
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306975 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6976 if (ioc->ioc_reset_in_progress) {
6977 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006978 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006979 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306980 ioc->ioc_reset_in_progress = 1;
6981 if (ioc->alt_ioc)
6982 ioc->alt_ioc->ioc_reset_in_progress = 1;
6983 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006984
6985 /* FIXME: If do_ioc_recovery fails, repeat....
6986 */
6987
6988 /* The SCSI driver needs to adjust timeouts on all current
6989 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006990 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006991 * For all other protocol drivers, this is a no-op.
6992 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05306993 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6994 if (MptResetHandlers[cb_idx]) {
6995 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
6996 if (ioc->alt_ioc)
6997 mpt_signal_reset(cb_idx, ioc->alt_ioc,
6998 MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006999 }
7000 }
7001
Kashyap, Desai2f187862009-05-29 16:52:37 +05307002 time_count = jiffies;
7003 rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
7004 if (rc != 0) {
7005 printk(KERN_WARNING MYNAM
7006 ": WARNING - (%d) Cannot recover %s\n", rc, ioc->name);
7007 } else {
7008 if (ioc->hard_resets < -1)
7009 ioc->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007010 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007011
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307012 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7013 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307014 ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307015 ioc->taskmgmt_in_progress = 0;
7016 if (ioc->alt_ioc) {
7017 ioc->alt_ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307018 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307019 ioc->alt_ioc->taskmgmt_in_progress = 0;
7020 }
7021 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007022
Kashyap, Desai2f187862009-05-29 16:52:37 +05307023 dtmprintk(ioc,
7024 printk(MYIOC_s_DEBUG_FMT
7025 "HardResetHandler: completed (%d seconds): %s\n", ioc->name,
7026 jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?
7027 "SUCCESS" : "FAILED")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007028
7029 return rc;
7030}
7031
Kashyap, Desai2f187862009-05-29 16:52:37 +05307032#ifdef CONFIG_FUSION_LOGGING
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007033static void
Kashyap, Desai2f187862009-05-29 16:52:37 +05307034mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007035{
Eric Moore509e5e52006-04-26 13:22:37 -06007036 char *ds = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307037 u32 evData0;
7038 int ii;
7039 u8 event;
7040 char *evStr = ioc->evStr;
7041
7042 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7043 evData0 = le32_to_cpu(pEventReply->Data[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007044
7045 switch(event) {
7046 case MPI_EVENT_NONE:
7047 ds = "None";
7048 break;
7049 case MPI_EVENT_LOG_DATA:
7050 ds = "Log Data";
7051 break;
7052 case MPI_EVENT_STATE_CHANGE:
7053 ds = "State Change";
7054 break;
7055 case MPI_EVENT_UNIT_ATTENTION:
7056 ds = "Unit Attention";
7057 break;
7058 case MPI_EVENT_IOC_BUS_RESET:
7059 ds = "IOC Bus Reset";
7060 break;
7061 case MPI_EVENT_EXT_BUS_RESET:
7062 ds = "External Bus Reset";
7063 break;
7064 case MPI_EVENT_RESCAN:
7065 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007066 break;
7067 case MPI_EVENT_LINK_STATUS_CHANGE:
7068 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
7069 ds = "Link Status(FAILURE) Change";
7070 else
7071 ds = "Link Status(ACTIVE) Change";
7072 break;
7073 case MPI_EVENT_LOOP_STATE_CHANGE:
7074 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
7075 ds = "Loop State(LIP) Change";
7076 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Kashyap, Desai2f187862009-05-29 16:52:37 +05307077 ds = "Loop State(LPE) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007078 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05307079 ds = "Loop State(LPB) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007080 break;
7081 case MPI_EVENT_LOGOUT:
7082 ds = "Logout";
7083 break;
7084 case MPI_EVENT_EVENT_CHANGE:
7085 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06007086 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007087 else
Eric Moore4f766dc2006-07-11 17:24:07 -06007088 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007089 break;
7090 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007091 {
7092 u8 ReasonCode = (u8)(evData0 >> 16);
7093 switch (ReasonCode) {
7094 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
7095 ds = "Integrated Raid: Volume Created";
7096 break;
7097 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
7098 ds = "Integrated Raid: Volume Deleted";
7099 break;
7100 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
7101 ds = "Integrated Raid: Volume Settings Changed";
7102 break;
7103 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
7104 ds = "Integrated Raid: Volume Status Changed";
7105 break;
7106 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
7107 ds = "Integrated Raid: Volume Physdisk Changed";
7108 break;
7109 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
7110 ds = "Integrated Raid: Physdisk Created";
7111 break;
7112 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
7113 ds = "Integrated Raid: Physdisk Deleted";
7114 break;
7115 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
7116 ds = "Integrated Raid: Physdisk Settings Changed";
7117 break;
7118 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
7119 ds = "Integrated Raid: Physdisk Status Changed";
7120 break;
7121 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
7122 ds = "Integrated Raid: Domain Validation Needed";
7123 break;
7124 case MPI_EVENT_RAID_RC_SMART_DATA :
7125 ds = "Integrated Raid; Smart Data";
7126 break;
7127 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
7128 ds = "Integrated Raid: Replace Action Started";
7129 break;
7130 default:
7131 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007132 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007133 }
7134 break;
7135 }
7136 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
7137 ds = "SCSI Device Status Change";
7138 break;
7139 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
7140 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007141 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007142 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007143 u8 ReasonCode = (u8)(evData0 >> 16);
7144 switch (ReasonCode) {
7145 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007146 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007147 "SAS Device Status Change: Added: "
7148 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007149 break;
7150 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06007151 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007152 "SAS Device Status Change: Deleted: "
7153 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007154 break;
7155 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06007156 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007157 "SAS Device Status Change: SMART Data: "
7158 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007159 break;
7160 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007161 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007162 "SAS Device Status Change: No Persistancy: "
7163 "id=%d channel=%d", id, channel);
7164 break;
7165 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
7166 snprintf(evStr, EVENT_DESCR_STR_SZ,
7167 "SAS Device Status Change: Unsupported Device "
7168 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007169 break;
7170 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
7171 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007172 "SAS Device Status Change: Internal Device "
7173 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007174 break;
7175 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
7176 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007177 "SAS Device Status Change: Internal Task "
7178 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007179 break;
7180 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
7181 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007182 "SAS Device Status Change: Internal Abort "
7183 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007184 break;
7185 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
7186 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007187 "SAS Device Status Change: Internal Clear "
7188 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007189 break;
7190 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
7191 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007192 "SAS Device Status Change: Internal Query "
7193 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007194 break;
7195 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007196 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007197 "SAS Device Status Change: Unknown: "
7198 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06007199 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007200 }
7201 break;
7202 }
7203 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
7204 ds = "Bus Timer Expired";
7205 break;
7206 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07007207 {
7208 u16 curr_depth = (u16)(evData0 >> 16);
7209 u8 channel = (u8)(evData0 >> 8);
7210 u8 id = (u8)(evData0);
7211
7212 snprintf(evStr, EVENT_DESCR_STR_SZ,
7213 "Queue Full: channel=%d id=%d depth=%d",
7214 channel, id, curr_depth);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007215 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07007216 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007217 case MPI_EVENT_SAS_SES:
7218 ds = "SAS SES Event";
7219 break;
7220 case MPI_EVENT_PERSISTENT_TABLE_FULL:
7221 ds = "Persistent Table Full";
7222 break;
7223 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07007224 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007225 u8 LinkRates = (u8)(evData0 >> 8);
7226 u8 PhyNumber = (u8)(evData0);
7227 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
7228 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
7229 switch (LinkRates) {
7230 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06007231 snprintf(evStr, EVENT_DESCR_STR_SZ,
7232 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007233 " Rate Unknown",PhyNumber);
7234 break;
7235 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06007236 snprintf(evStr, EVENT_DESCR_STR_SZ,
7237 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007238 " Phy Disabled",PhyNumber);
7239 break;
7240 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06007241 snprintf(evStr, EVENT_DESCR_STR_SZ,
7242 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007243 " Failed Speed Nego",PhyNumber);
7244 break;
7245 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06007246 snprintf(evStr, EVENT_DESCR_STR_SZ,
7247 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007248 " Sata OOB Completed",PhyNumber);
7249 break;
7250 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06007251 snprintf(evStr, EVENT_DESCR_STR_SZ,
7252 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007253 " Rate 1.5 Gbps",PhyNumber);
7254 break;
7255 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06007256 snprintf(evStr, EVENT_DESCR_STR_SZ,
7257 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007258 " Rate 3.0 Gpbs",PhyNumber);
7259 break;
7260 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007261 snprintf(evStr, EVENT_DESCR_STR_SZ,
7262 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007263 break;
7264 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007265 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007266 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007267 case MPI_EVENT_SAS_DISCOVERY_ERROR:
7268 ds = "SAS Discovery Error";
7269 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007270 case MPI_EVENT_IR_RESYNC_UPDATE:
7271 {
7272 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06007273 snprintf(evStr, EVENT_DESCR_STR_SZ,
7274 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07007275 break;
7276 }
7277 case MPI_EVENT_IR2:
7278 {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307279 u8 id = (u8)(evData0);
7280 u8 channel = (u8)(evData0 >> 8);
7281 u8 phys_num = (u8)(evData0 >> 24);
Moore, Eric3a892be2006-03-14 09:14:03 -07007282 u8 ReasonCode = (u8)(evData0 >> 16);
Kashyap, Desai2f187862009-05-29 16:52:37 +05307283
Moore, Eric3a892be2006-03-14 09:14:03 -07007284 switch (ReasonCode) {
7285 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307286 snprintf(evStr, EVENT_DESCR_STR_SZ,
7287 "IR2: LD State Changed: "
7288 "id=%d channel=%d phys_num=%d",
7289 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007290 break;
7291 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307292 snprintf(evStr, EVENT_DESCR_STR_SZ,
7293 "IR2: PD State Changed "
7294 "id=%d channel=%d phys_num=%d",
7295 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007296 break;
7297 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307298 snprintf(evStr, EVENT_DESCR_STR_SZ,
7299 "IR2: Bad Block Table Full: "
7300 "id=%d channel=%d phys_num=%d",
7301 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007302 break;
7303 case MPI_EVENT_IR2_RC_PD_INSERTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307304 snprintf(evStr, EVENT_DESCR_STR_SZ,
7305 "IR2: PD Inserted: "
7306 "id=%d channel=%d phys_num=%d",
7307 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007308 break;
7309 case MPI_EVENT_IR2_RC_PD_REMOVED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307310 snprintf(evStr, EVENT_DESCR_STR_SZ,
7311 "IR2: PD Removed: "
7312 "id=%d channel=%d phys_num=%d",
7313 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007314 break;
7315 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307316 snprintf(evStr, EVENT_DESCR_STR_SZ,
7317 "IR2: Foreign CFG Detected: "
7318 "id=%d channel=%d phys_num=%d",
7319 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007320 break;
7321 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307322 snprintf(evStr, EVENT_DESCR_STR_SZ,
7323 "IR2: Rebuild Medium Error: "
7324 "id=%d channel=%d phys_num=%d",
7325 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007326 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05307327 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
7328 snprintf(evStr, EVENT_DESCR_STR_SZ,
7329 "IR2: Dual Port Added: "
7330 "id=%d channel=%d phys_num=%d",
7331 id, channel, phys_num);
7332 break;
7333 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
7334 snprintf(evStr, EVENT_DESCR_STR_SZ,
7335 "IR2: Dual Port Removed: "
7336 "id=%d channel=%d phys_num=%d",
7337 id, channel, phys_num);
7338 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007339 default:
7340 ds = "IR2";
7341 break;
7342 }
7343 break;
7344 }
7345 case MPI_EVENT_SAS_DISCOVERY:
7346 {
7347 if (evData0)
7348 ds = "SAS Discovery: Start";
7349 else
7350 ds = "SAS Discovery: Stop";
7351 break;
7352 }
7353 case MPI_EVENT_LOG_ENTRY_ADDED:
7354 ds = "SAS Log Entry Added";
7355 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007356
Eric Moorec6c727a2007-01-29 09:44:54 -07007357 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
7358 {
7359 u8 phy_num = (u8)(evData0);
7360 u8 port_num = (u8)(evData0 >> 8);
7361 u8 port_width = (u8)(evData0 >> 16);
7362 u8 primative = (u8)(evData0 >> 24);
7363 snprintf(evStr, EVENT_DESCR_STR_SZ,
7364 "SAS Broadcase Primative: phy=%d port=%d "
7365 "width=%d primative=0x%02x",
7366 phy_num, port_num, port_width, primative);
7367 break;
7368 }
7369
7370 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7371 {
7372 u8 reason = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007373
Kashyap, Desai2f187862009-05-29 16:52:37 +05307374 switch (reason) {
7375 case MPI_EVENT_SAS_INIT_RC_ADDED:
7376 ds = "SAS Initiator Status Change: Added";
7377 break;
7378 case MPI_EVENT_SAS_INIT_RC_REMOVED:
7379 ds = "SAS Initiator Status Change: Deleted";
7380 break;
7381 default:
7382 ds = "SAS Initiator Status Change";
7383 break;
7384 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007385 break;
7386 }
7387
7388 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7389 {
7390 u8 max_init = (u8)(evData0);
7391 u8 current_init = (u8)(evData0 >> 8);
7392
7393 snprintf(evStr, EVENT_DESCR_STR_SZ,
7394 "SAS Initiator Device Table Overflow: max initiators=%02d "
7395 "current initators=%02d",
7396 max_init, current_init);
7397 break;
7398 }
7399 case MPI_EVENT_SAS_SMP_ERROR:
7400 {
7401 u8 status = (u8)(evData0);
7402 u8 port_num = (u8)(evData0 >> 8);
7403 u8 result = (u8)(evData0 >> 16);
7404
7405 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7406 snprintf(evStr, EVENT_DESCR_STR_SZ,
7407 "SAS SMP Error: port=%d result=0x%02x",
7408 port_num, result);
7409 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7410 snprintf(evStr, EVENT_DESCR_STR_SZ,
7411 "SAS SMP Error: port=%d : CRC Error",
7412 port_num);
7413 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7414 snprintf(evStr, EVENT_DESCR_STR_SZ,
7415 "SAS SMP Error: port=%d : Timeout",
7416 port_num);
7417 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7418 snprintf(evStr, EVENT_DESCR_STR_SZ,
7419 "SAS SMP Error: port=%d : No Destination",
7420 port_num);
7421 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7422 snprintf(evStr, EVENT_DESCR_STR_SZ,
7423 "SAS SMP Error: port=%d : Bad Destination",
7424 port_num);
7425 else
7426 snprintf(evStr, EVENT_DESCR_STR_SZ,
7427 "SAS SMP Error: port=%d : status=0x%02x",
7428 port_num, status);
7429 break;
7430 }
7431
Kashyap, Desai2f187862009-05-29 16:52:37 +05307432 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
7433 {
7434 u8 reason = (u8)(evData0);
7435
7436 switch (reason) {
7437 case MPI_EVENT_SAS_EXP_RC_ADDED:
7438 ds = "Expander Status Change: Added";
7439 break;
7440 case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
7441 ds = "Expander Status Change: Deleted";
7442 break;
7443 default:
7444 ds = "Expander Status Change";
7445 break;
7446 }
7447 break;
7448 }
7449
Linus Torvalds1da177e2005-04-16 15:20:36 -07007450 /*
7451 * MPT base "custom" events may be added here...
7452 */
7453 default:
7454 ds = "Unknown";
7455 break;
7456 }
Eric Moore509e5e52006-04-26 13:22:37 -06007457 if (ds)
7458 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007459
Kashyap, Desai2f187862009-05-29 16:52:37 +05307460
7461 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7462 "MPT event:(%02Xh) : %s\n",
7463 ioc->name, event, evStr));
7464
7465 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
7466 ": Event data:\n"));
7467 for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
7468 devtverboseprintk(ioc, printk(" %08x",
7469 le32_to_cpu(pEventReply->Data[ii])));
7470 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
7471}
7472#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007473/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007474/**
7475 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007476 * @ioc: Pointer to MPT_ADAPTER structure
7477 * @pEventReply: Pointer to EventNotification reply frame
7478 * @evHandlers: Pointer to integer, number of event handlers
7479 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007480 * Routes a received EventNotificationReply to all currently registered
7481 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007482 * Returns sum of event handlers return values.
7483 */
7484static int
7485ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7486{
7487 u16 evDataLen;
7488 u32 evData0 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007489 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307490 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007491 int r = 0;
7492 int handlers = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007493 u8 event;
7494
7495 /*
7496 * Do platform normalization of values
7497 */
7498 event = le32_to_cpu(pEventReply->Event) & 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007499 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7500 if (evDataLen) {
7501 evData0 = le32_to_cpu(pEventReply->Data[0]);
7502 }
7503
Prakash, Sathya436ace72007-07-24 15:42:08 +05307504#ifdef CONFIG_FUSION_LOGGING
Kashyap, Desai2f187862009-05-29 16:52:37 +05307505 if (evDataLen)
7506 mpt_display_event_info(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007507#endif
7508
7509 /*
7510 * Do general / base driver event processing
7511 */
7512 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007513 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7514 if (evDataLen) {
7515 u8 evState = evData0 & 0xFF;
7516
7517 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7518
7519 /* Update EventState field in cached IocFacts */
7520 if (ioc->facts.Function) {
7521 ioc->facts.EventState = evState;
7522 }
7523 }
7524 break;
Moore, Ericece50912006-01-16 18:53:19 -07007525 case MPI_EVENT_INTEGRATED_RAID:
7526 mptbase_raid_process_event_data(ioc,
7527 (MpiEventDataRaid_t *)pEventReply->Data);
7528 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007529 default:
7530 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007531 }
7532
7533 /*
7534 * Should this event be logged? Events are written sequentially.
7535 * When buffer is full, start again at the top.
7536 */
7537 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7538 int idx;
7539
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007540 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007541
7542 ioc->events[idx].event = event;
7543 ioc->events[idx].eventContext = ioc->eventContext;
7544
7545 for (ii = 0; ii < 2; ii++) {
7546 if (ii < evDataLen)
7547 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7548 else
7549 ioc->events[idx].data[ii] = 0;
7550 }
7551
7552 ioc->eventContext++;
7553 }
7554
7555
7556 /*
7557 * Call each currently registered protocol event handler.
7558 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007559 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307560 if (MptEvHandlers[cb_idx]) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307561 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7562 "Routing Event to event handler #%d\n",
7563 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307564 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007565 handlers++;
7566 }
7567 }
7568 /* FIXME? Examine results here? */
7569
7570 /*
7571 * If needed, send (a single) EventAck.
7572 */
7573 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307574 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007575 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007576 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307577 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007578 ioc->name, ii));
7579 }
7580 }
7581
7582 *evHandlers = handlers;
7583 return r;
7584}
7585
7586/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007587/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007588 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7589 * @ioc: Pointer to MPT_ADAPTER structure
7590 * @log_info: U32 LogInfo reply word from the IOC
7591 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007592 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007593 */
7594static void
7595mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7596{
Eric Moore7c431e52007-06-13 16:34:36 -06007597 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007598
Eric Moore7c431e52007-06-13 16:34:36 -06007599 switch (log_info & 0xFF000000) {
7600 case MPI_IOCLOGINFO_FC_INIT_BASE:
7601 desc = "FCP Initiator";
7602 break;
7603 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7604 desc = "FCP Target";
7605 break;
7606 case MPI_IOCLOGINFO_FC_LAN_BASE:
7607 desc = "LAN";
7608 break;
7609 case MPI_IOCLOGINFO_FC_MSG_BASE:
7610 desc = "MPI Message Layer";
7611 break;
7612 case MPI_IOCLOGINFO_FC_LINK_BASE:
7613 desc = "FC Link";
7614 break;
7615 case MPI_IOCLOGINFO_FC_CTX_BASE:
7616 desc = "Context Manager";
7617 break;
7618 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7619 desc = "Invalid Field Offset";
7620 break;
7621 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7622 desc = "State Change Info";
7623 break;
7624 }
7625
7626 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7627 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007628}
7629
7630/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007631/**
Moore, Eric335a9412006-01-17 17:06:23 -07007632 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007633 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007634 * @log_info: U32 LogInfo word from the IOC
7635 *
7636 * Refer to lsi/sp_log.h.
7637 */
7638static void
Moore, Eric335a9412006-01-17 17:06:23 -07007639mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007640{
7641 u32 info = log_info & 0x00FF0000;
7642 char *desc = "unknown";
7643
7644 switch (info) {
7645 case 0x00010000:
7646 desc = "bug! MID not found";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007647 break;
7648
7649 case 0x00020000:
7650 desc = "Parity Error";
7651 break;
7652
7653 case 0x00030000:
7654 desc = "ASYNC Outbound Overrun";
7655 break;
7656
7657 case 0x00040000:
7658 desc = "SYNC Offset Error";
7659 break;
7660
7661 case 0x00050000:
7662 desc = "BM Change";
7663 break;
7664
7665 case 0x00060000:
7666 desc = "Msg In Overflow";
7667 break;
7668
7669 case 0x00070000:
7670 desc = "DMA Error";
7671 break;
7672
7673 case 0x00080000:
7674 desc = "Outbound DMA Overrun";
7675 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007676
Linus Torvalds1da177e2005-04-16 15:20:36 -07007677 case 0x00090000:
7678 desc = "Task Management";
7679 break;
7680
7681 case 0x000A0000:
7682 desc = "Device Problem";
7683 break;
7684
7685 case 0x000B0000:
7686 desc = "Invalid Phase Change";
7687 break;
7688
7689 case 0x000C0000:
7690 desc = "Untagged Table Size";
7691 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007692
Linus Torvalds1da177e2005-04-16 15:20:36 -07007693 }
7694
7695 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7696}
7697
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007698/* strings for sas loginfo */
7699 static char *originator_str[] = {
7700 "IOP", /* 00h */
7701 "PL", /* 01h */
7702 "IR" /* 02h */
7703 };
7704 static char *iop_code_str[] = {
7705 NULL, /* 00h */
7706 "Invalid SAS Address", /* 01h */
7707 NULL, /* 02h */
7708 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007709 "Diag Message Error", /* 04h */
7710 "Task Terminated", /* 05h */
7711 "Enclosure Management", /* 06h */
7712 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007713 };
7714 static char *pl_code_str[] = {
7715 NULL, /* 00h */
7716 "Open Failure", /* 01h */
7717 "Invalid Scatter Gather List", /* 02h */
7718 "Wrong Relative Offset or Frame Length", /* 03h */
7719 "Frame Transfer Error", /* 04h */
7720 "Transmit Frame Connected Low", /* 05h */
7721 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7722 "SATA Read Log Receive Data Error", /* 07h */
7723 "SATA NCQ Fail All Commands After Error", /* 08h */
7724 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7725 "Receive Frame Invalid Message", /* 0Ah */
7726 "Receive Context Message Valid Error", /* 0Bh */
7727 "Receive Frame Current Frame Error", /* 0Ch */
7728 "SATA Link Down", /* 0Dh */
7729 "Discovery SATA Init W IOS", /* 0Eh */
7730 "Config Invalid Page", /* 0Fh */
7731 "Discovery SATA Init Timeout", /* 10h */
7732 "Reset", /* 11h */
7733 "Abort", /* 12h */
7734 "IO Not Yet Executed", /* 13h */
7735 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007736 "Persistent Reservation Out Not Affiliation "
7737 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007738 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007739 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007740 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007741 NULL, /* 19h */
7742 NULL, /* 1Ah */
7743 NULL, /* 1Bh */
7744 NULL, /* 1Ch */
7745 NULL, /* 1Dh */
7746 NULL, /* 1Eh */
7747 NULL, /* 1Fh */
7748 "Enclosure Management" /* 20h */
7749 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007750 static char *ir_code_str[] = {
7751 "Raid Action Error", /* 00h */
7752 NULL, /* 00h */
7753 NULL, /* 01h */
7754 NULL, /* 02h */
7755 NULL, /* 03h */
7756 NULL, /* 04h */
7757 NULL, /* 05h */
7758 NULL, /* 06h */
7759 NULL /* 07h */
7760 };
7761 static char *raid_sub_code_str[] = {
7762 NULL, /* 00h */
7763 "Volume Creation Failed: Data Passed too "
7764 "Large", /* 01h */
7765 "Volume Creation Failed: Duplicate Volumes "
7766 "Attempted", /* 02h */
7767 "Volume Creation Failed: Max Number "
7768 "Supported Volumes Exceeded", /* 03h */
7769 "Volume Creation Failed: DMA Error", /* 04h */
7770 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7771 "Volume Creation Failed: Error Reading "
7772 "MFG Page 4", /* 06h */
7773 "Volume Creation Failed: Creating Internal "
7774 "Structures", /* 07h */
7775 NULL, /* 08h */
7776 NULL, /* 09h */
7777 NULL, /* 0Ah */
7778 NULL, /* 0Bh */
7779 NULL, /* 0Ch */
7780 NULL, /* 0Dh */
7781 NULL, /* 0Eh */
7782 NULL, /* 0Fh */
7783 "Activation failed: Already Active Volume", /* 10h */
7784 "Activation failed: Unsupported Volume Type", /* 11h */
7785 "Activation failed: Too Many Active Volumes", /* 12h */
7786 "Activation failed: Volume ID in Use", /* 13h */
7787 "Activation failed: Reported Failure", /* 14h */
7788 "Activation failed: Importing a Volume", /* 15h */
7789 NULL, /* 16h */
7790 NULL, /* 17h */
7791 NULL, /* 18h */
7792 NULL, /* 19h */
7793 NULL, /* 1Ah */
7794 NULL, /* 1Bh */
7795 NULL, /* 1Ch */
7796 NULL, /* 1Dh */
7797 NULL, /* 1Eh */
7798 NULL, /* 1Fh */
7799 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7800 "Phys Disk failed: Data Passed too Large", /* 21h */
7801 "Phys Disk failed: DMA Error", /* 22h */
7802 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7803 "Phys Disk failed: Creating Phys Disk Config "
7804 "Page", /* 24h */
7805 NULL, /* 25h */
7806 NULL, /* 26h */
7807 NULL, /* 27h */
7808 NULL, /* 28h */
7809 NULL, /* 29h */
7810 NULL, /* 2Ah */
7811 NULL, /* 2Bh */
7812 NULL, /* 2Ch */
7813 NULL, /* 2Dh */
7814 NULL, /* 2Eh */
7815 NULL, /* 2Fh */
7816 "Compatibility Error: IR Disabled", /* 30h */
7817 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7818 "Compatibility Error: Device not Direct Access "
7819 "Device ", /* 32h */
7820 "Compatibility Error: Removable Device Found", /* 33h */
7821 "Compatibility Error: Device SCSI Version not "
7822 "2 or Higher", /* 34h */
7823 "Compatibility Error: SATA Device, 48 BIT LBA "
7824 "not Supported", /* 35h */
7825 "Compatibility Error: Device doesn't have "
7826 "512 Byte Block Sizes", /* 36h */
7827 "Compatibility Error: Volume Type Check Failed", /* 37h */
7828 "Compatibility Error: Volume Type is "
7829 "Unsupported by FW", /* 38h */
7830 "Compatibility Error: Disk Drive too Small for "
7831 "use in Volume", /* 39h */
7832 "Compatibility Error: Phys Disk for Create "
7833 "Volume not Found", /* 3Ah */
7834 "Compatibility Error: Too Many or too Few "
7835 "Disks for Volume Type", /* 3Bh */
7836 "Compatibility Error: Disk stripe Sizes "
7837 "Must be 64KB", /* 3Ch */
7838 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7839 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007840
7841/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007842/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007843 * mpt_sas_log_info - Log information returned from SAS IOC.
7844 * @ioc: Pointer to MPT_ADAPTER structure
7845 * @log_info: U32 LogInfo reply word from the IOC
7846 *
7847 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007848 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007849static void
7850mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7851{
7852union loginfo_type {
7853 u32 loginfo;
7854 struct {
7855 u32 subcode:16;
7856 u32 code:8;
7857 u32 originator:4;
7858 u32 bus_type:4;
7859 }dw;
7860};
7861 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007862 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007863 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007864 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007865
7866 sas_loginfo.loginfo = log_info;
7867 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007868 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007869 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007870
7871 originator_desc = originator_str[sas_loginfo.dw.originator];
7872
7873 switch (sas_loginfo.dw.originator) {
7874
7875 case 0: /* IOP */
7876 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007877 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007878 code_desc = iop_code_str[sas_loginfo.dw.code];
7879 break;
7880 case 1: /* PL */
7881 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007882 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007883 code_desc = pl_code_str[sas_loginfo.dw.code];
7884 break;
7885 case 2: /* IR */
7886 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007887 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007888 break;
7889 code_desc = ir_code_str[sas_loginfo.dw.code];
7890 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007891 ARRAY_SIZE(raid_sub_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007892 break;
7893 if (sas_loginfo.dw.code == 0)
7894 sub_code_desc =
7895 raid_sub_code_str[sas_loginfo.dw.subcode];
7896 break;
7897 default:
7898 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007899 }
7900
Eric Moorec6c727a2007-01-29 09:44:54 -07007901 if (sub_code_desc != NULL)
7902 printk(MYIOC_s_INFO_FMT
7903 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7904 " SubCode={%s}\n",
7905 ioc->name, log_info, originator_desc, code_desc,
7906 sub_code_desc);
7907 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007908 printk(MYIOC_s_INFO_FMT
7909 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7910 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007911 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007912 sas_loginfo.dw.subcode);
7913 else
7914 printk(MYIOC_s_INFO_FMT
7915 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7916 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007917 ioc->name, log_info, originator_desc,
7918 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007919}
7920
Linus Torvalds1da177e2005-04-16 15:20:36 -07007921/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007922/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007923 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7924 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007925 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007926 * @mf: Pointer to MPT request frame
7927 *
7928 * Refer to lsi/mpi.h.
7929 **/
7930static void
7931mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7932{
7933 Config_t *pReq = (Config_t *)mf;
7934 char extend_desc[EVENT_DESCR_STR_SZ];
7935 char *desc = NULL;
7936 u32 form;
7937 u8 page_type;
7938
7939 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7940 page_type = pReq->ExtPageType;
7941 else
7942 page_type = pReq->Header.PageType;
7943
7944 /*
7945 * ignore invalid page messages for GET_NEXT_HANDLE
7946 */
7947 form = le32_to_cpu(pReq->PageAddress);
7948 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7949 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7950 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7951 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7952 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7953 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7954 return;
7955 }
7956 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7957 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7958 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7959 return;
7960 }
7961
7962 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7963 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7964 page_type, pReq->Header.PageNumber, pReq->Action, form);
7965
7966 switch (ioc_status) {
7967
7968 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7969 desc = "Config Page Invalid Action";
7970 break;
7971
7972 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7973 desc = "Config Page Invalid Type";
7974 break;
7975
7976 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7977 desc = "Config Page Invalid Page";
7978 break;
7979
7980 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7981 desc = "Config Page Invalid Data";
7982 break;
7983
7984 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7985 desc = "Config Page No Defaults";
7986 break;
7987
7988 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7989 desc = "Config Page Can't Commit";
7990 break;
7991 }
7992
7993 if (!desc)
7994 return;
7995
Eric Moore29dd3602007-09-14 18:46:51 -06007996 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7997 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007998}
7999
8000/**
8001 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07008002 * @ioc: Pointer to MPT_ADAPTER structure
8003 * @ioc_status: U32 IOCStatus word from IOC
8004 * @mf: Pointer to MPT request frame
8005 *
8006 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008007 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07008008static void
Eric Moorec6c727a2007-01-29 09:44:54 -07008009mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008010{
8011 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06008012 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008013
8014 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07008015
8016/****************************************************************************/
8017/* Common IOCStatus values for all replies */
8018/****************************************************************************/
8019
Linus Torvalds1da177e2005-04-16 15:20:36 -07008020 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
8021 desc = "Invalid Function";
8022 break;
8023
8024 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
8025 desc = "Busy";
8026 break;
8027
8028 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
8029 desc = "Invalid SGL";
8030 break;
8031
8032 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
8033 desc = "Internal Error";
8034 break;
8035
8036 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
8037 desc = "Reserved";
8038 break;
8039
8040 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
8041 desc = "Insufficient Resources";
8042 break;
8043
8044 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
8045 desc = "Invalid Field";
8046 break;
8047
8048 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
8049 desc = "Invalid State";
8050 break;
8051
Eric Moorec6c727a2007-01-29 09:44:54 -07008052/****************************************************************************/
8053/* Config IOCStatus values */
8054/****************************************************************************/
8055
Linus Torvalds1da177e2005-04-16 15:20:36 -07008056 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8057 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8058 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8059 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8060 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8061 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008062 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008063 break;
8064
Eric Moorec6c727a2007-01-29 09:44:54 -07008065/****************************************************************************/
8066/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
8067/* */
8068/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
8069/* */
8070/****************************************************************************/
8071
Linus Torvalds1da177e2005-04-16 15:20:36 -07008072 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008073 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008074 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
8075 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
8076 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
8077 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008078 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008079 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008080 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008081 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008082 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008083 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07008084 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008085 break;
8086
Eric Moorec6c727a2007-01-29 09:44:54 -07008087/****************************************************************************/
8088/* SCSI Target values */
8089/****************************************************************************/
8090
8091 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
8092 desc = "Target: Priority IO";
8093 break;
8094
8095 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
8096 desc = "Target: Invalid Port";
8097 break;
8098
8099 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
8100 desc = "Target Invalid IO Index:";
8101 break;
8102
8103 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
8104 desc = "Target: Aborted";
8105 break;
8106
8107 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
8108 desc = "Target: No Conn Retryable";
8109 break;
8110
8111 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
8112 desc = "Target: No Connection";
8113 break;
8114
8115 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
8116 desc = "Target: Transfer Count Mismatch";
8117 break;
8118
8119 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
8120 desc = "Target: STS Data not Sent";
8121 break;
8122
8123 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
8124 desc = "Target: Data Offset Error";
8125 break;
8126
8127 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
8128 desc = "Target: Too Much Write Data";
8129 break;
8130
8131 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
8132 desc = "Target: IU Too Short";
8133 break;
8134
8135 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
8136 desc = "Target: ACK NAK Timeout";
8137 break;
8138
8139 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
8140 desc = "Target: Nak Received";
8141 break;
8142
8143/****************************************************************************/
8144/* Fibre Channel Direct Access values */
8145/****************************************************************************/
8146
8147 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
8148 desc = "FC: Aborted";
8149 break;
8150
8151 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
8152 desc = "FC: RX ID Invalid";
8153 break;
8154
8155 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
8156 desc = "FC: DID Invalid";
8157 break;
8158
8159 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
8160 desc = "FC: Node Logged Out";
8161 break;
8162
8163 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
8164 desc = "FC: Exchange Canceled";
8165 break;
8166
8167/****************************************************************************/
8168/* LAN values */
8169/****************************************************************************/
8170
8171 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
8172 desc = "LAN: Device not Found";
8173 break;
8174
8175 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
8176 desc = "LAN: Device Failure";
8177 break;
8178
8179 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
8180 desc = "LAN: Transmit Error";
8181 break;
8182
8183 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
8184 desc = "LAN: Transmit Aborted";
8185 break;
8186
8187 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
8188 desc = "LAN: Receive Error";
8189 break;
8190
8191 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
8192 desc = "LAN: Receive Aborted";
8193 break;
8194
8195 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
8196 desc = "LAN: Partial Packet";
8197 break;
8198
8199 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
8200 desc = "LAN: Canceled";
8201 break;
8202
8203/****************************************************************************/
8204/* Serial Attached SCSI values */
8205/****************************************************************************/
8206
8207 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
8208 desc = "SAS: SMP Request Failed";
8209 break;
8210
8211 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
8212 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07008213 break;
8214
8215 default:
8216 desc = "Others";
8217 break;
8218 }
Eric Moorec6c727a2007-01-29 09:44:54 -07008219
8220 if (!desc)
8221 return;
8222
Eric Moore29dd3602007-09-14 18:46:51 -06008223 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
8224 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008225}
8226
8227/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008228EXPORT_SYMBOL(mpt_attach);
8229EXPORT_SYMBOL(mpt_detach);
8230#ifdef CONFIG_PM
8231EXPORT_SYMBOL(mpt_resume);
8232EXPORT_SYMBOL(mpt_suspend);
8233#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07008234EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008235EXPORT_SYMBOL(mpt_register);
8236EXPORT_SYMBOL(mpt_deregister);
8237EXPORT_SYMBOL(mpt_event_register);
8238EXPORT_SYMBOL(mpt_event_deregister);
8239EXPORT_SYMBOL(mpt_reset_register);
8240EXPORT_SYMBOL(mpt_reset_deregister);
8241EXPORT_SYMBOL(mpt_device_driver_register);
8242EXPORT_SYMBOL(mpt_device_driver_deregister);
8243EXPORT_SYMBOL(mpt_get_msg_frame);
8244EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05308245EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008246EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008247EXPORT_SYMBOL(mpt_send_handshake_request);
8248EXPORT_SYMBOL(mpt_verify_adapter);
8249EXPORT_SYMBOL(mpt_GetIocState);
8250EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008251EXPORT_SYMBOL(mpt_HardResetHandler);
8252EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008253EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008254EXPORT_SYMBOL(mpt_alloc_fw_memory);
8255EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02008256EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07008257EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008258
Linus Torvalds1da177e2005-04-16 15:20:36 -07008259/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008260/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008261 * fusion_init - Fusion MPT base driver initialization routine.
8262 *
8263 * Returns 0 for success, non-zero for failure.
8264 */
8265static int __init
8266fusion_init(void)
8267{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308268 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008269
8270 show_mptmod_ver(my_NAME, my_VERSION);
8271 printk(KERN_INFO COPYRIGHT "\n");
8272
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308273 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
8274 MptCallbacks[cb_idx] = NULL;
8275 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
8276 MptEvHandlers[cb_idx] = NULL;
8277 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008278 }
8279
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008280 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07008281 * EventNotification handling.
8282 */
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05308283 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008284
8285 /* Register for hard reset handling callbacks.
8286 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05308287 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008288
8289#ifdef CONFIG_PROC_FS
8290 (void) procmpt_create();
8291#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008292 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008293}
8294
8295/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008296/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008297 * fusion_exit - Perform driver unload cleanup.
8298 *
8299 * This routine frees all resources associated with each MPT adapter
8300 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
8301 */
8302static void __exit
8303fusion_exit(void)
8304{
8305
Linus Torvalds1da177e2005-04-16 15:20:36 -07008306 mpt_reset_deregister(mpt_base_index);
8307
8308#ifdef CONFIG_PROC_FS
8309 procmpt_destroy();
8310#endif
8311}
8312
Linus Torvalds1da177e2005-04-16 15:20:36 -07008313module_init(fusion_init);
8314module_exit(fusion_exit);