blob: 44b9315044579639e9e1e10463887f866c38c9ef [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 Hellwig82ffb6712005-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 Hellwig82ffb6712005-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 Hellwig82ffb6712005-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 Hellwig82ffb6712005-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/**
1026 * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr
1027 * (1078 workaround).
1028 * @pAddr: virtual address for SGE
1029 * @flagslength: SGE flags and data transfer length
1030 * @dma_addr: Physical address
1031 *
1032 * This routine places a MPT request frame back on the MPT adapter's
1033 * FreeQ.
1034 **/
1035static void
1036mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1037{
1038 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1039 u32 tmp;
1040
1041 pSge->Address.Low = cpu_to_le32
1042 (lower_32_bits((unsigned long)(dma_addr)));
1043 tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
1044
1045 /*
1046 * 1078 errata workaround for the 36GB limitation
1047 */
1048 if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {
1049 flagslength |=
1050 MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
1051 tmp |= (1<<31);
1052 if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
1053 printk(KERN_DEBUG "1078 P0M2 addressing for "
1054 "addr = 0x%llx len = %d\n",
1055 (unsigned long long)dma_addr,
1056 MPI_SGE_LENGTH(flagslength));
1057 }
1058
1059 pSge->Address.High = cpu_to_le32(tmp);
1060 pSge->FlagsLength = cpu_to_le32(
1061 (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1062}
1063
1064/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1065/**
1066 * mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
1067 * @pAddr: virtual address for SGE
1068 * @next: nextChainOffset value (u32's)
1069 * @length: length of next SGL segment
1070 * @dma_addr: Physical address
1071 *
1072 */
1073static void
1074mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1075{
1076 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
1077 pChain->Length = cpu_to_le16(length);
1078 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
1079 pChain->NextChainOffset = next;
1080 pChain->Address = cpu_to_le32(dma_addr);
1081}
1082
1083/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1084/**
1085 * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
1086 * @pAddr: virtual address for SGE
1087 * @next: nextChainOffset value (u32's)
1088 * @length: length of next SGL segment
1089 * @dma_addr: Physical address
1090 *
1091 */
1092static void
1093mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1094{
1095 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 u32 tmp = dma_addr & 0xFFFFFFFF;
1097
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301098 pChain->Length = cpu_to_le16(length);
1099 pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
1100 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301102 pChain->NextChainOffset = next;
1103
1104 pChain->Address.Low = cpu_to_le32(tmp);
1105 tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
1106 pChain->Address.High = cpu_to_le32(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107}
1108
1109/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1110/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001111 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301112 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 * @ioc: Pointer to MPT adapter structure
1114 * @reqBytes: Size of the request in bytes
1115 * @req: Pointer to MPT request frame
1116 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1117 *
1118 * This routine is used exclusively to send MptScsiTaskMgmt
1119 * requests since they are required to be sent via doorbell handshake.
1120 *
1121 * NOTE: It is the callers responsibility to byte-swap fields in the
1122 * request which are greater than 1 byte in size.
1123 *
1124 * Returns 0 for success, non-zero for failure.
1125 */
1126int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301127mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128{
Eric Moorecd2c6192007-01-29 09:47:47 -07001129 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 u8 *req_as_bytes;
1131 int ii;
1132
1133 /* State is known to be good upon entering
1134 * this function so issue the bus reset
1135 * request.
1136 */
1137
1138 /*
1139 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1140 * setting cb_idx/req_idx. But ONLY if this request
1141 * is in proper (pre-alloc'd) request buffer range...
1142 */
1143 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1144 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1145 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1146 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301147 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 }
1149
1150 /* Make sure there are no doorbells */
1151 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001152
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1154 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1155 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1156
1157 /* Wait for IOC doorbell int */
1158 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1159 return ii;
1160 }
1161
1162 /* Read doorbell and check for active bit */
1163 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1164 return -5;
1165
Eric Moore29dd3602007-09-14 18:46:51 -06001166 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001167 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
1169 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1170
1171 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1172 return -2;
1173 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001174
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 /* Send request via doorbell handshake */
1176 req_as_bytes = (u8 *) req;
1177 for (ii = 0; ii < reqBytes/4; ii++) {
1178 u32 word;
1179
1180 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1181 (req_as_bytes[(ii*4) + 1] << 8) |
1182 (req_as_bytes[(ii*4) + 2] << 16) |
1183 (req_as_bytes[(ii*4) + 3] << 24));
1184 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1185 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1186 r = -3;
1187 break;
1188 }
1189 }
1190
1191 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1192 r = 0;
1193 else
1194 r = -4;
1195
1196 /* Make sure there are no doorbells */
1197 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001198
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 return r;
1200}
1201
1202/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1203/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001204 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001205 * @ioc: Pointer to MPT adapter structure
1206 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001207 * @sleepFlag: Specifies whether the process can sleep
1208 *
1209 * Provides mechanism for the host driver to control the IOC's
1210 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001211 *
1212 * Access Control Value - bits[15:12]
1213 * 0h Reserved
1214 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1215 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1216 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1217 *
1218 * Returns 0 for success, non-zero for failure.
1219 */
1220
1221static int
1222mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1223{
1224 int r = 0;
1225
1226 /* return if in use */
1227 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1228 & MPI_DOORBELL_ACTIVE)
1229 return -1;
1230
1231 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1232
1233 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1234 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1235 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1236 (access_control_value<<12)));
1237
1238 /* Wait for IOC to clear Doorbell Status bit */
1239 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1240 return -2;
1241 }else
1242 return 0;
1243}
1244
1245/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1246/**
1247 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001248 * @ioc: Pointer to pointer to IOC adapter
1249 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001250 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001251 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001252 * Returns 0 for success, non-zero for failure.
1253 */
1254static int
1255mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1256{
1257 char *psge;
1258 int flags_length;
1259 u32 host_page_buffer_sz=0;
1260
1261 if(!ioc->HostPageBuffer) {
1262
1263 host_page_buffer_sz =
1264 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1265
1266 if(!host_page_buffer_sz)
1267 return 0; /* fw doesn't need any host buffers */
1268
1269 /* spin till we get enough memory */
1270 while(host_page_buffer_sz > 0) {
1271
1272 if((ioc->HostPageBuffer = pci_alloc_consistent(
1273 ioc->pcidev,
1274 host_page_buffer_sz,
1275 &ioc->HostPageBuffer_dma)) != NULL) {
1276
Prakash, Sathya436ace72007-07-24 15:42:08 +05301277 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001278 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001279 ioc->name, ioc->HostPageBuffer,
1280 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001281 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001282 ioc->alloc_total += host_page_buffer_sz;
1283 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1284 break;
1285 }
1286
1287 host_page_buffer_sz -= (4*1024);
1288 }
1289 }
1290
1291 if(!ioc->HostPageBuffer) {
1292 printk(MYIOC_s_ERR_FMT
1293 "Failed to alloc memory for host_page_buffer!\n",
1294 ioc->name);
1295 return -999;
1296 }
1297
1298 psge = (char *)&ioc_init->HostPageBufferSGE;
1299 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1300 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1301 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1302 MPI_SGE_FLAGS_HOST_TO_IOC |
1303 MPI_SGE_FLAGS_END_OF_BUFFER;
1304 if (sizeof(dma_addr_t) == sizeof(u64)) {
1305 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1306 }
1307 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1308 flags_length |= ioc->HostPageBuffer_sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301309 ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001310 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1311
1312return 0;
1313}
1314
1315/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1316/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001317 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 * @iocid: IOC unique identifier (integer)
1319 * @iocpp: Pointer to pointer to IOC adapter
1320 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001321 * Given a unique IOC identifier, set pointer to the associated MPT
1322 * adapter structure.
1323 *
1324 * Returns iocid and sets iocpp if iocid is found.
1325 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 */
1327int
1328mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1329{
1330 MPT_ADAPTER *ioc;
1331
1332 list_for_each_entry(ioc,&ioc_list,list) {
1333 if (ioc->id == iocid) {
1334 *iocpp =ioc;
1335 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001336 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001338
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 *iocpp = NULL;
1340 return -1;
1341}
1342
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301343/**
1344 * mpt_get_product_name - returns product string
1345 * @vendor: pci vendor id
1346 * @device: pci device id
1347 * @revision: pci revision id
1348 * @prod_name: string returned
1349 *
1350 * Returns product string displayed when driver loads,
1351 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1352 *
1353 **/
1354static void
1355mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1356{
1357 char *product_str = NULL;
1358
1359 if (vendor == PCI_VENDOR_ID_BROCADE) {
1360 switch (device)
1361 {
1362 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1363 switch (revision)
1364 {
1365 case 0x00:
1366 product_str = "BRE040 A0";
1367 break;
1368 case 0x01:
1369 product_str = "BRE040 A1";
1370 break;
1371 default:
1372 product_str = "BRE040";
1373 break;
1374 }
1375 break;
1376 }
1377 goto out;
1378 }
1379
1380 switch (device)
1381 {
1382 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1383 product_str = "LSIFC909 B1";
1384 break;
1385 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1386 product_str = "LSIFC919 B0";
1387 break;
1388 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1389 product_str = "LSIFC929 B0";
1390 break;
1391 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1392 if (revision < 0x80)
1393 product_str = "LSIFC919X A0";
1394 else
1395 product_str = "LSIFC919XL A1";
1396 break;
1397 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1398 if (revision < 0x80)
1399 product_str = "LSIFC929X A0";
1400 else
1401 product_str = "LSIFC929XL A1";
1402 break;
1403 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1404 product_str = "LSIFC939X A1";
1405 break;
1406 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1407 product_str = "LSIFC949X A1";
1408 break;
1409 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1410 switch (revision)
1411 {
1412 case 0x00:
1413 product_str = "LSIFC949E A0";
1414 break;
1415 case 0x01:
1416 product_str = "LSIFC949E A1";
1417 break;
1418 default:
1419 product_str = "LSIFC949E";
1420 break;
1421 }
1422 break;
1423 case MPI_MANUFACTPAGE_DEVID_53C1030:
1424 switch (revision)
1425 {
1426 case 0x00:
1427 product_str = "LSI53C1030 A0";
1428 break;
1429 case 0x01:
1430 product_str = "LSI53C1030 B0";
1431 break;
1432 case 0x03:
1433 product_str = "LSI53C1030 B1";
1434 break;
1435 case 0x07:
1436 product_str = "LSI53C1030 B2";
1437 break;
1438 case 0x08:
1439 product_str = "LSI53C1030 C0";
1440 break;
1441 case 0x80:
1442 product_str = "LSI53C1030T A0";
1443 break;
1444 case 0x83:
1445 product_str = "LSI53C1030T A2";
1446 break;
1447 case 0x87:
1448 product_str = "LSI53C1030T A3";
1449 break;
1450 case 0xc1:
1451 product_str = "LSI53C1020A A1";
1452 break;
1453 default:
1454 product_str = "LSI53C1030";
1455 break;
1456 }
1457 break;
1458 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1459 switch (revision)
1460 {
1461 case 0x03:
1462 product_str = "LSI53C1035 A2";
1463 break;
1464 case 0x04:
1465 product_str = "LSI53C1035 B0";
1466 break;
1467 default:
1468 product_str = "LSI53C1035";
1469 break;
1470 }
1471 break;
1472 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1473 switch (revision)
1474 {
1475 case 0x00:
1476 product_str = "LSISAS1064 A1";
1477 break;
1478 case 0x01:
1479 product_str = "LSISAS1064 A2";
1480 break;
1481 case 0x02:
1482 product_str = "LSISAS1064 A3";
1483 break;
1484 case 0x03:
1485 product_str = "LSISAS1064 A4";
1486 break;
1487 default:
1488 product_str = "LSISAS1064";
1489 break;
1490 }
1491 break;
1492 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1493 switch (revision)
1494 {
1495 case 0x00:
1496 product_str = "LSISAS1064E A0";
1497 break;
1498 case 0x01:
1499 product_str = "LSISAS1064E B0";
1500 break;
1501 case 0x02:
1502 product_str = "LSISAS1064E B1";
1503 break;
1504 case 0x04:
1505 product_str = "LSISAS1064E B2";
1506 break;
1507 case 0x08:
1508 product_str = "LSISAS1064E B3";
1509 break;
1510 default:
1511 product_str = "LSISAS1064E";
1512 break;
1513 }
1514 break;
1515 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1516 switch (revision)
1517 {
1518 case 0x00:
1519 product_str = "LSISAS1068 A0";
1520 break;
1521 case 0x01:
1522 product_str = "LSISAS1068 B0";
1523 break;
1524 case 0x02:
1525 product_str = "LSISAS1068 B1";
1526 break;
1527 default:
1528 product_str = "LSISAS1068";
1529 break;
1530 }
1531 break;
1532 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1533 switch (revision)
1534 {
1535 case 0x00:
1536 product_str = "LSISAS1068E A0";
1537 break;
1538 case 0x01:
1539 product_str = "LSISAS1068E B0";
1540 break;
1541 case 0x02:
1542 product_str = "LSISAS1068E B1";
1543 break;
1544 case 0x04:
1545 product_str = "LSISAS1068E B2";
1546 break;
1547 case 0x08:
1548 product_str = "LSISAS1068E B3";
1549 break;
1550 default:
1551 product_str = "LSISAS1068E";
1552 break;
1553 }
1554 break;
1555 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1556 switch (revision)
1557 {
1558 case 0x00:
1559 product_str = "LSISAS1078 A0";
1560 break;
1561 case 0x01:
1562 product_str = "LSISAS1078 B0";
1563 break;
1564 case 0x02:
1565 product_str = "LSISAS1078 C0";
1566 break;
1567 case 0x03:
1568 product_str = "LSISAS1078 C1";
1569 break;
1570 case 0x04:
1571 product_str = "LSISAS1078 C2";
1572 break;
1573 default:
1574 product_str = "LSISAS1078";
1575 break;
1576 }
1577 break;
1578 }
1579
1580 out:
1581 if (product_str)
1582 sprintf(prod_name, "%s", product_str);
1583}
1584
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301585/**
1586 * mpt_mapresources - map in memory mapped io
1587 * @ioc: Pointer to pointer to IOC adapter
1588 *
1589 **/
1590static int
1591mpt_mapresources(MPT_ADAPTER *ioc)
1592{
1593 u8 __iomem *mem;
1594 int ii;
1595 unsigned long mem_phys;
1596 unsigned long port;
1597 u32 msize;
1598 u32 psize;
1599 u8 revision;
1600 int r = -ENODEV;
1601 struct pci_dev *pdev;
1602
1603 pdev = ioc->pcidev;
1604 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1605 if (pci_enable_device_mem(pdev)) {
1606 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1607 "failed\n", ioc->name);
1608 return r;
1609 }
1610 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1611 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1612 "MEM failed\n", ioc->name);
1613 return r;
1614 }
1615
1616 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1617
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301618 if (sizeof(dma_addr_t) > 4) {
1619 const uint64_t required_mask = dma_get_required_mask
1620 (&pdev->dev);
1621 if (required_mask > DMA_BIT_MASK(32)
1622 && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
1623 && !pci_set_consistent_dma_mask(pdev,
1624 DMA_BIT_MASK(64))) {
1625 ioc->dma_mask = DMA_BIT_MASK(64);
1626 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1627 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1628 ioc->name));
1629 } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1630 && !pci_set_consistent_dma_mask(pdev,
1631 DMA_BIT_MASK(32))) {
1632 ioc->dma_mask = DMA_BIT_MASK(32);
1633 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1634 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1635 ioc->name));
1636 } else {
1637 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1638 ioc->name, pci_name(pdev));
1639 return r;
1640 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301641 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301642 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1643 && !pci_set_consistent_dma_mask(pdev,
1644 DMA_BIT_MASK(32))) {
1645 ioc->dma_mask = DMA_BIT_MASK(32);
1646 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1647 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1648 ioc->name));
1649 } else {
1650 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1651 ioc->name, pci_name(pdev));
1652 return r;
1653 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301654 }
1655
1656 mem_phys = msize = 0;
1657 port = psize = 0;
1658 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1659 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1660 if (psize)
1661 continue;
1662 /* Get I/O space! */
1663 port = pci_resource_start(pdev, ii);
1664 psize = pci_resource_len(pdev, ii);
1665 } else {
1666 if (msize)
1667 continue;
1668 /* Get memmap */
1669 mem_phys = pci_resource_start(pdev, ii);
1670 msize = pci_resource_len(pdev, ii);
1671 }
1672 }
1673 ioc->mem_size = msize;
1674
1675 mem = NULL;
1676 /* Get logical ptr for PciMem0 space */
1677 /*mem = ioremap(mem_phys, msize);*/
1678 mem = ioremap(mem_phys, msize);
1679 if (mem == NULL) {
1680 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1681 " memory!\n", ioc->name);
1682 return -EINVAL;
1683 }
1684 ioc->memmap = mem;
1685 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n",
1686 ioc->name, mem, mem_phys));
1687
1688 ioc->mem_phys = mem_phys;
1689 ioc->chip = (SYSIF_REGS __iomem *)mem;
1690
1691 /* Save Port IO values in case we need to do downloadboot */
1692 ioc->pio_mem_phys = port;
1693 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1694
1695 return 0;
1696}
1697
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001699/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001700 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001702 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 *
1704 * This routine performs all the steps necessary to bring the IOC of
1705 * a MPT adapter to a OPERATIONAL state. This includes registering
1706 * memory regions, registering the interrupt, and allocating request
1707 * and reply memory pools.
1708 *
1709 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1710 * MPT adapter.
1711 *
1712 * Returns 0 for success, non-zero for failure.
1713 *
1714 * TODO: Add support for polled controllers
1715 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001716int
1717mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718{
1719 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301720 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 u8 revision;
1723 u8 pcixcmd;
1724 static int mpt_ids = 0;
1725#ifdef CONFIG_PROC_FS
1726 struct proc_dir_entry *dent, *ent;
1727#endif
1728
Jesper Juhl56876192007-08-10 14:50:51 -07001729 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1730 if (ioc == NULL) {
1731 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1732 return -ENOMEM;
1733 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301734
Eric Moore29dd3602007-09-14 18:46:51 -06001735 ioc->id = mpt_ids++;
1736 sprintf(ioc->name, "ioc%d", ioc->id);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301737 dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Jesper Juhl56876192007-08-10 14:50:51 -07001738
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301739 /*
1740 * set initial debug level
1741 * (refer to mptdebug.h)
1742 *
1743 */
1744 ioc->debug_level = mpt_debug_level;
1745 if (mpt_debug_level)
1746 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301747
Eric Moore29dd3602007-09-14 18:46:51 -06001748 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001749
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301750 ioc->pcidev = pdev;
1751 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001752 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 return r;
1754 }
1755
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301756 /*
1757 * Setting up proper handlers for scatter gather handling
1758 */
1759 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
1760 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
1761 ioc->add_sge = &mpt_add_sge_64bit_1078;
1762 else
1763 ioc->add_sge = &mpt_add_sge_64bit;
1764 ioc->add_chain = &mpt_add_chain_64bit;
1765 ioc->sg_addr_size = 8;
1766 } else {
1767 ioc->add_sge = &mpt_add_sge;
1768 ioc->add_chain = &mpt_add_chain;
1769 ioc->sg_addr_size = 4;
1770 }
1771 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
1772
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 ioc->alloc_total = sizeof(MPT_ADAPTER);
1774 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1775 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001776
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 ioc->pcidev = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301779 spin_lock_init(&ioc->taskmgmt_lock);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05301780 mutex_init(&ioc->internal_cmds.mutex);
1781 init_completion(&ioc->internal_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301782 mutex_init(&ioc->mptbase_cmds.mutex);
1783 init_completion(&ioc->mptbase_cmds.done);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301784 mutex_init(&ioc->taskmgmt_cmds.mutex);
1785 init_completion(&ioc->taskmgmt_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301786
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 /* Initialize the event logging.
1788 */
1789 ioc->eventTypes = 0; /* None */
1790 ioc->eventContext = 0;
1791 ioc->eventLogSize = 0;
1792 ioc->events = NULL;
1793
1794#ifdef MFCNT
1795 ioc->mfcnt = 0;
1796#endif
1797
Kashyap, Desai2f187862009-05-29 16:52:37 +05301798 ioc->sh = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 ioc->cached_fw = NULL;
1800
1801 /* Initilize SCSI Config Data structure
1802 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001803 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804
Michael Reed05e8ec12006-01-13 14:31:54 -06001805 /* Initialize the fc rport list head.
1806 */
1807 INIT_LIST_HEAD(&ioc->fc_rports);
1808
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 /* Find lookup slot. */
1810 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001811
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301812
1813 /* Initialize workqueue */
1814 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301815
Kashyap, Desai2f187862009-05-29 16:52:37 +05301816 snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN,
Kay Sieversaab0de22008-05-02 06:02:41 +02001817 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301818 ioc->reset_work_q =
1819 create_singlethread_workqueue(ioc->reset_work_q_name);
1820 if (!ioc->reset_work_q) {
1821 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1822 ioc->name);
1823 pci_release_selected_regions(pdev, ioc->bars);
1824 kfree(ioc);
1825 return -ENOMEM;
1826 }
1827
Eric Moore29dd3602007-09-14 18:46:51 -06001828 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1829 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301831 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1832 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1833
1834 switch (pdev->device)
1835 {
1836 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1837 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1838 ioc->errata_flag_1064 = 1;
1839 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1840 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1841 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1842 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301844 break;
1845
1846 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 /* 929X Chip Fix. Set Split transactions level
1849 * for PCIX. Set MOST bits to zero.
1850 */
1851 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1852 pcixcmd &= 0x8F;
1853 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1854 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 /* 929XL Chip Fix. Set MMRBC to 0x08.
1856 */
1857 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1858 pcixcmd |= 0x08;
1859 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1860 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301862 break;
1863
1864 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 /* 919X Chip Fix. Set Split transactions level
1866 * for PCIX. Set MOST bits to zero.
1867 */
1868 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1869 pcixcmd &= 0x8F;
1870 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001871 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301872 break;
1873
1874 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 /* 1030 Chip Fix. Disable Split transactions
1876 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1877 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 if (revision < C0_1030) {
1879 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1880 pcixcmd &= 0x8F;
1881 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1882 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301883
1884 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001885 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301886 break;
1887
1888 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1889 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001890 ioc->errata_flag_1064 = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301891 ioc->bus_type = SAS;
1892 break;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301893
1894 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1895 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1896 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001897 ioc->bus_type = SAS;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301898 break;
Eric Moore87cf8982006-06-27 16:09:26 -06001899 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301901
Kashyap, Desaie3829682009-01-08 14:27:16 +05301902 switch (ioc->bus_type) {
1903
1904 case SAS:
1905 ioc->msi_enable = mpt_msi_enable_sas;
1906 break;
1907
1908 case SPI:
1909 ioc->msi_enable = mpt_msi_enable_spi;
1910 break;
1911
1912 case FC:
1913 ioc->msi_enable = mpt_msi_enable_fc;
1914 break;
1915
1916 default:
1917 ioc->msi_enable = 0;
1918 break;
1919 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001920 if (ioc->errata_flag_1064)
1921 pci_disable_io_access(pdev);
1922
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 spin_lock_init(&ioc->FreeQlock);
1924
1925 /* Disable all! */
1926 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1927 ioc->active = 0;
1928 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1929
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301930 /* Set IOC ptr in the pcidev's driver data. */
1931 pci_set_drvdata(ioc->pcidev, ioc);
1932
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 /* Set lookup ptr. */
1934 list_add_tail(&ioc->list, &ioc_list);
1935
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001936 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 */
1938 mpt_detect_bound_ports(ioc, pdev);
1939
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301940 INIT_LIST_HEAD(&ioc->fw_event_list);
1941 spin_lock_init(&ioc->fw_event_lock);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301942 snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301943 ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
1944
James Bottomleyc92f2222006-03-01 09:02:49 -06001945 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1946 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001947 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1948 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001949
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001951 if (ioc->alt_ioc)
1952 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301953 iounmap(ioc->memmap);
1954 if (r != -5)
1955 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301956
1957 destroy_workqueue(ioc->reset_work_q);
1958 ioc->reset_work_q = NULL;
1959
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 kfree(ioc);
1961 pci_set_drvdata(pdev, NULL);
1962 return r;
1963 }
1964
1965 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001966 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301967 if(MptDeviceDriverHandlers[cb_idx] &&
1968 MptDeviceDriverHandlers[cb_idx]->probe) {
1969 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 }
1971 }
1972
1973#ifdef CONFIG_PROC_FS
1974 /*
1975 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1976 */
1977 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1978 if (dent) {
1979 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1980 if (ent) {
1981 ent->read_proc = procmpt_iocinfo_read;
1982 ent->data = ioc;
1983 }
1984 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1985 if (ent) {
1986 ent->read_proc = procmpt_summary_read;
1987 ent->data = ioc;
1988 }
1989 }
1990#endif
1991
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301992 if (!ioc->alt_ioc)
1993 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1994 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1995
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 return 0;
1997}
1998
1999/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002000/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002001 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 */
2004
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002005void
2006mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007{
2008 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2009 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302010 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302011 unsigned long flags;
2012 struct workqueue_struct *wq;
2013
2014 /*
2015 * Stop polling ioc for fault condition
2016 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302017 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302018 wq = ioc->reset_work_q;
2019 ioc->reset_work_q = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302020 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302021 cancel_delayed_work(&ioc->fault_reset_work);
2022 destroy_workqueue(wq);
2023
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05302024 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2025 wq = ioc->fw_event_q;
2026 ioc->fw_event_q = NULL;
2027 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2028 destroy_workqueue(wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029
2030 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2031 remove_proc_entry(pname, NULL);
2032 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2033 remove_proc_entry(pname, NULL);
2034 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2035 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002036
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002038 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302039 if(MptDeviceDriverHandlers[cb_idx] &&
2040 MptDeviceDriverHandlers[cb_idx]->remove) {
2041 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 }
2043 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002044
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 /* Disable interrupts! */
2046 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2047
2048 ioc->active = 0;
2049 synchronize_irq(pdev->irq);
2050
2051 /* Clear any lingering interrupt */
2052 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2053
2054 CHIPREG_READ32(&ioc->chip->IntStatus);
2055
2056 mpt_adapter_dispose(ioc);
2057
2058 pci_set_drvdata(pdev, NULL);
2059}
2060
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061/**************************************************************************
2062 * Power Management
2063 */
2064#ifdef CONFIG_PM
2065/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002066/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002067 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002068 * @pdev: Pointer to pci_dev structure
2069 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002071int
2072mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073{
2074 u32 device_state;
2075 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302077 device_state = pci_choose_state(pdev, state);
2078 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2079 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2080 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081
2082 /* put ioc into READY_STATE */
2083 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2084 printk(MYIOC_s_ERR_FMT
2085 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2086 }
2087
2088 /* disable interrupts */
2089 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2090 ioc->active = 0;
2091
2092 /* Clear any lingering interrupt */
2093 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2094
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302095 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002096 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302097 pci_disable_msi(ioc->pcidev);
2098 ioc->pci_irq = -1;
2099 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302101 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 return 0;
2104}
2105
2106/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002107/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002108 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002109 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002111int
2112mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113{
2114 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2115 u32 device_state = pdev->current_state;
2116 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302117 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002118
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302119 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2120 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2121 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302123 pci_set_power_state(pdev, PCI_D0);
2124 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302126 ioc->pcidev = pdev;
2127 err = mpt_mapresources(ioc);
2128 if (err)
2129 return err;
2130
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302131 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2132 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2133 ioc->add_sge = &mpt_add_sge_64bit_1078;
2134 else
2135 ioc->add_sge = &mpt_add_sge_64bit;
2136 ioc->add_chain = &mpt_add_chain_64bit;
2137 ioc->sg_addr_size = 8;
2138 } else {
2139
2140 ioc->add_sge = &mpt_add_sge;
2141 ioc->add_chain = &mpt_add_chain;
2142 ioc->sg_addr_size = 4;
2143 }
2144 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2145
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302146 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2147 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2148 CHIPREG_READ32(&ioc->chip->Doorbell));
2149
2150 /*
2151 * Errata workaround for SAS pci express:
2152 * Upon returning to the D0 state, the contents of the doorbell will be
2153 * stale data, and this will incorrectly signal to the host driver that
2154 * the firmware is ready to process mpt commands. The workaround is
2155 * to issue a diagnostic reset.
2156 */
2157 if (ioc->bus_type == SAS && (pdev->device ==
2158 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2159 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2160 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2161 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2162 ioc->name);
2163 goto out;
2164 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166
2167 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302168 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2169 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2170 CAN_SLEEP);
2171 if (recovery_state != 0)
2172 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2173 "error:[%x]\n", ioc->name, recovery_state);
2174 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302176 "pci-resume: success\n", ioc->name);
2177 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302179
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180}
2181#endif
2182
James Bottomley4ff42a62006-05-17 18:06:52 -05002183static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302184mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002185{
2186 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2187 ioc->bus_type != SPI) ||
2188 (MptDriverClass[index] == MPTFC_DRIVER &&
2189 ioc->bus_type != FC) ||
2190 (MptDriverClass[index] == MPTSAS_DRIVER &&
2191 ioc->bus_type != SAS))
2192 /* make sure we only call the relevant reset handler
2193 * for the bus */
2194 return 0;
2195 return (MptResetHandlers[index])(ioc, reset_phase);
2196}
2197
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002199/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2201 * @ioc: Pointer to MPT adapter structure
2202 * @reason: Event word / reason
2203 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2204 *
2205 * This routine performs all the steps necessary to bring the IOC
2206 * to a OPERATIONAL state.
2207 *
2208 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2209 * MPT adapter.
2210 *
2211 * Returns:
2212 * 0 for success
2213 * -1 if failed to get board READY
2214 * -2 if READY but IOCFacts Failed
2215 * -3 if READY but PrimeIOCFifos Failed
2216 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302217 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302218 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 */
2220static int
2221mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2222{
2223 int hard_reset_done = 0;
2224 int alt_ioc_ready = 0;
2225 int hard;
2226 int rc=0;
2227 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302228 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 int handlers;
2230 int ret = 0;
2231 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002232 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302233 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
Eric Moore29dd3602007-09-14 18:46:51 -06002235 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2236 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237
2238 /* Disable reply interrupts (also blocks FreeQ) */
2239 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2240 ioc->active = 0;
2241
2242 if (ioc->alt_ioc) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302243 if (ioc->alt_ioc->active ||
2244 reason == MPT_HOSTEVENT_IOC_RECOVER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 reset_alt_ioc_active = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302246 /* Disable alt-IOC's reply interrupts
2247 * (and FreeQ) for a bit
2248 **/
2249 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2250 0xFFFFFFFF);
2251 ioc->alt_ioc->active = 0;
2252 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 }
2254
2255 hard = 1;
2256 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2257 hard = 0;
2258
2259 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2260 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002261 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2262 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263
2264 if (reset_alt_ioc_active && ioc->alt_ioc) {
2265 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002266 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2267 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002268 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 ioc->alt_ioc->active = 1;
2270 }
2271
2272 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302273 printk(MYIOC_s_WARN_FMT
2274 "NOT READY WARNING!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302276 ret = -1;
2277 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 }
2279
2280 /* hard_reset_done = 0 if a soft reset was performed
2281 * and 1 if a hard reset was performed.
2282 */
2283 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2284 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2285 alt_ioc_ready = 1;
2286 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05302287 printk(MYIOC_s_WARN_FMT
2288 ": alt-ioc Not ready WARNING!\n",
2289 ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 }
2291
2292 for (ii=0; ii<5; ii++) {
2293 /* Get IOC facts! Allow 5 retries */
2294 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2295 break;
2296 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002297
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298
2299 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002300 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2301 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 ret = -2;
2303 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2304 MptDisplayIocCapabilities(ioc);
2305 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002306
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 if (alt_ioc_ready) {
2308 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302309 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302310 "Initial Alt IocFacts failed rc=%x\n",
2311 ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 /* Retry - alt IOC was initialized once
2313 */
2314 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2315 }
2316 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302317 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002318 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 alt_ioc_ready = 0;
2320 reset_alt_ioc_active = 0;
2321 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2322 MptDisplayIocCapabilities(ioc->alt_ioc);
2323 }
2324 }
2325
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302326 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2327 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2328 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2329 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2330 IORESOURCE_IO);
2331 if (pci_enable_device(ioc->pcidev))
2332 return -5;
2333 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2334 "mpt"))
2335 return -5;
2336 }
2337
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002338 /*
2339 * Device is reset now. It must have de-asserted the interrupt line
2340 * (if it was asserted) and it should be safe to register for the
2341 * interrupt now.
2342 */
2343 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2344 ioc->pci_irq = -1;
2345 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302346 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002347 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002348 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302349 else
2350 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002351 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002352 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002353 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002354 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Kashyap, Desai2f187862009-05-29 16:52:37 +05302355 "interrupt %d!\n",
2356 ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302357 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002358 pci_disable_msi(ioc->pcidev);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302359 ret = -EBUSY;
2360 goto out;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002361 }
2362 irq_allocated = 1;
2363 ioc->pci_irq = ioc->pcidev->irq;
2364 pci_set_master(ioc->pcidev); /* ?? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302365 pci_set_drvdata(ioc->pcidev, ioc);
2366 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2367 "installed at interrupt %d\n", ioc->name,
2368 ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002369 }
2370 }
2371
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 /* Prime reply & request queues!
2373 * (mucho alloc's) Must be done prior to
2374 * init as upper addresses are needed for init.
2375 * If fails, continue with alt-ioc processing
2376 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302377 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
2378 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2380 ret = -3;
2381
2382 /* May need to check/upload firmware & data here!
2383 * If fails, continue with alt-ioc processing
2384 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302385 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
2386 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2388 ret = -4;
2389// NEW!
2390 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302391 printk(MYIOC_s_WARN_FMT
2392 ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002393 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 alt_ioc_ready = 0;
2395 reset_alt_ioc_active = 0;
2396 }
2397
2398 if (alt_ioc_ready) {
2399 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2400 alt_ioc_ready = 0;
2401 reset_alt_ioc_active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302402 printk(MYIOC_s_WARN_FMT
2403 ": alt-ioc: (%d) init failure WARNING!\n",
2404 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 }
2406 }
2407
2408 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2409 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302410 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002411 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412
2413 /* Controller is not operational, cannot do upload
2414 */
2415 if (ret == 0) {
2416 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002417 if (rc == 0) {
2418 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2419 /*
2420 * Maintain only one pointer to FW memory
2421 * so there will not be two attempt to
2422 * downloadboot onboard dual function
2423 * chips (mpt_adapter_disable,
2424 * mpt_diag_reset)
2425 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302426 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002427 "mpt_upload: alt_%s has cached_fw=%p \n",
2428 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302429 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002430 }
2431 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002432 printk(MYIOC_s_WARN_FMT
2433 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302434 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 }
2437 }
2438 }
2439
Kashyap, Desaifd761752009-05-29 16:39:06 +05302440 /* Enable MPT base driver management of EventNotification
2441 * and EventAck handling.
2442 */
2443 if ((ret == 0) && (!ioc->facts.EventState)) {
2444 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2445 "SendEventNotification\n",
2446 ioc->name));
2447 ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
2448 }
2449
2450 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2451 rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
2452
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 if (ret == 0) {
2454 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002455 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 ioc->active = 1;
2457 }
Kashyap, Desaifd761752009-05-29 16:39:06 +05302458 if (rc == 0) { /* alt ioc */
2459 if (reset_alt_ioc_active && ioc->alt_ioc) {
2460 /* (re)Enable alt-IOC! (reply interrupt) */
2461 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
2462 "reply irq re-enabled\n",
2463 ioc->alt_ioc->name));
2464 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2465 MPI_HIM_DIM);
2466 ioc->alt_ioc->active = 1;
2467 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 }
2469
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002471 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2473 * recursive scenario; GetLanConfigPages times out, timer expired
2474 * routine calls HardResetHandler, which calls into here again,
2475 * and we try GetLanConfigPages again...
2476 */
2477 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002478
2479 /*
2480 * Initalize link list for inactive raid volumes.
2481 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002482 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002483 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2484
Kashyap, Desai2f187862009-05-29 16:52:37 +05302485 switch (ioc->bus_type) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002486
Kashyap, Desai2f187862009-05-29 16:52:37 +05302487 case SAS:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002488 /* clear persistency table */
2489 if(ioc->facts.IOCExceptions &
2490 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2491 ret = mptbase_sas_persist_operation(ioc,
2492 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2493 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002494 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002495 }
2496
2497 /* Find IM volumes
2498 */
2499 mpt_findImVolumes(ioc);
2500
Kashyap, Desai2f187862009-05-29 16:52:37 +05302501 /* Check, and possibly reset, the coalescing value
2502 */
2503 mpt_read_ioc_pg_1(ioc);
2504
2505 break;
2506
2507 case FC:
2508 if ((ioc->pfacts[0].ProtocolFlags &
2509 MPI_PORTFACTS_PROTOCOL_LAN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2511 /*
2512 * Pre-fetch the ports LAN MAC address!
2513 * (LANPage1_t stuff)
2514 */
2515 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302516 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2517 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302518 "LanAddr = %02X:%02X:%02X"
2519 ":%02X:%02X:%02X\n",
2520 ioc->name, a[5], a[4],
2521 a[3], a[2], a[1], a[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302523 break;
2524
2525 case SPI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 /* Get NVRAM and adapter maximums from SPP 0 and 2
2527 */
2528 mpt_GetScsiPortSettings(ioc, 0);
2529
2530 /* Get version and length of SDP 1
2531 */
2532 mpt_readScsiDevicePageHeaders(ioc, 0);
2533
2534 /* Find IM volumes
2535 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002536 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 mpt_findImVolumes(ioc);
2538
2539 /* Check, and possibly reset, the coalescing value
2540 */
2541 mpt_read_ioc_pg_1(ioc);
2542
2543 mpt_read_ioc_pg_4(ioc);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302544
2545 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 }
2547
2548 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302549 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 }
2551
2552 /*
2553 * Call each currently registered protocol IOC reset handler
2554 * with post-reset indication.
2555 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2556 * MptResetHandlers[] registered yet.
2557 */
2558 if (hard_reset_done) {
2559 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302560 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2561 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302562 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002563 "Calling IOC post_reset handler #%d\n",
2564 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302565 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 handlers++;
2567 }
2568
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302569 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302570 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002571 "Calling IOC post_reset handler #%d\n",
2572 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302573 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 handlers++;
2575 }
2576 }
2577 /* FIXME? Examine results here? */
2578 }
2579
Eric Moore0ccdb002006-07-11 17:33:13 -06002580 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002581 if ((ret != 0) && irq_allocated) {
2582 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302583 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002584 pci_disable_msi(ioc->pcidev);
2585 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 return ret;
2587}
2588
2589/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002590/**
2591 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 * @ioc: Pointer to MPT adapter structure
2593 * @pdev: Pointer to (struct pci_dev) structure
2594 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002595 * Search for PCI bus/dev_function which matches
2596 * PCI bus/dev_function (+/-1) for newly discovered 929,
2597 * 929X, 1030 or 1035.
2598 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2600 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2601 */
2602static void
2603mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2604{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002605 struct pci_dev *peer=NULL;
2606 unsigned int slot = PCI_SLOT(pdev->devfn);
2607 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 MPT_ADAPTER *ioc_srch;
2609
Prakash, Sathya436ace72007-07-24 15:42:08 +05302610 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002611 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002612 ioc->name, pci_name(pdev), pdev->bus->number,
2613 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002614
2615 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2616 if (!peer) {
2617 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2618 if (!peer)
2619 return;
2620 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621
2622 list_for_each_entry(ioc_srch, &ioc_list, list) {
2623 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002624 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 /* Paranoia checks */
2626 if (ioc->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302627 printk(MYIOC_s_WARN_FMT
2628 "Oops, already bound (%s <==> %s)!\n",
2629 ioc->name, ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 break;
2631 } else if (ioc_srch->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302632 printk(MYIOC_s_WARN_FMT
2633 "Oops, already bound (%s <==> %s)!\n",
2634 ioc_srch->name, ioc_srch->name,
2635 ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 break;
2637 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302638 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2639 "FOUND! binding %s <==> %s\n",
2640 ioc->name, ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 ioc_srch->alt_ioc = ioc;
2642 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 }
2644 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002645 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646}
2647
2648/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002649/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002651 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 */
2653static void
2654mpt_adapter_disable(MPT_ADAPTER *ioc)
2655{
2656 int sz;
2657 int ret;
2658
2659 if (ioc->cached_fw != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302660 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2661 "%s: Pushing FW onto adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302662 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2663 ioc->cached_fw, CAN_SLEEP)) < 0) {
2664 printk(MYIOC_s_WARN_FMT
2665 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002666 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 }
2668 }
2669
Kashyap, Desai71278192009-05-29 16:53:14 +05302670 /*
2671 * Put the controller into ready state (if its not already)
2672 */
2673 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {
2674 if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
2675 CAN_SLEEP)) {
2676 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)
2677 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit "
2678 "reset failed to put ioc in ready state!\n",
2679 ioc->name, __func__);
2680 } else
2681 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset "
2682 "failed!\n", ioc->name, __func__);
2683 }
2684
2685
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 /* Disable adapter interrupts! */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302687 synchronize_irq(ioc->pcidev->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2689 ioc->active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302690
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 /* Clear any lingering interrupt */
2692 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302693 CHIPREG_READ32(&ioc->chip->IntStatus);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694
2695 if (ioc->alloc != NULL) {
2696 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002697 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2698 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 pci_free_consistent(ioc->pcidev, sz,
2700 ioc->alloc, ioc->alloc_dma);
2701 ioc->reply_frames = NULL;
2702 ioc->req_frames = NULL;
2703 ioc->alloc = NULL;
2704 ioc->alloc_total -= sz;
2705 }
2706
2707 if (ioc->sense_buf_pool != NULL) {
2708 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2709 pci_free_consistent(ioc->pcidev, sz,
2710 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2711 ioc->sense_buf_pool = NULL;
2712 ioc->alloc_total -= sz;
2713 }
2714
2715 if (ioc->events != NULL){
2716 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2717 kfree(ioc->events);
2718 ioc->events = NULL;
2719 ioc->alloc_total -= sz;
2720 }
2721
Prakash, Sathya984621b2008-01-11 14:42:17 +05302722 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002724 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002725 mpt_inactive_raid_list_free(ioc);
2726 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002727 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002728 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002729 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730
2731 if (ioc->spi_data.pIocPg4 != NULL) {
2732 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302733 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 ioc->spi_data.pIocPg4,
2735 ioc->spi_data.IocPg4_dma);
2736 ioc->spi_data.pIocPg4 = NULL;
2737 ioc->alloc_total -= sz;
2738 }
2739
2740 if (ioc->ReqToChain != NULL) {
2741 kfree(ioc->ReqToChain);
2742 kfree(ioc->RequestNB);
2743 ioc->ReqToChain = NULL;
2744 }
2745
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002746 kfree(ioc->ChainToChain);
2747 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002748
2749 if (ioc->HostPageBuffer != NULL) {
2750 if((ret = mpt_host_page_access_control(ioc,
2751 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002752 printk(MYIOC_s_ERR_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302753 ": %s: host page buffers free failed (%d)!\n",
2754 ioc->name, __func__, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002755 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302756 dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2757 "HostPageBuffer free @ %p, sz=%d bytes\n",
2758 ioc->name, ioc->HostPageBuffer,
2759 ioc->HostPageBuffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002760 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002761 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002762 ioc->HostPageBuffer = NULL;
2763 ioc->HostPageBuffer_sz = 0;
2764 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2765 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766
Kashyap, Desai2f187862009-05-29 16:52:37 +05302767 pci_set_drvdata(ioc->pcidev, NULL);
2768}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002770/**
2771 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 * @ioc: Pointer to MPT adapter structure
2773 *
2774 * This routine unregisters h/w resources and frees all alloc'd memory
2775 * associated with a MPT adapter structure.
2776 */
2777static void
2778mpt_adapter_dispose(MPT_ADAPTER *ioc)
2779{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002780 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002782 if (ioc == NULL)
2783 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002785 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002787 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002789 if (ioc->pci_irq != -1) {
2790 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302791 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002792 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002793 ioc->pci_irq = -1;
2794 }
2795
2796 if (ioc->memmap != NULL) {
2797 iounmap(ioc->memmap);
2798 ioc->memmap = NULL;
2799 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302801 pci_disable_device(ioc->pcidev);
2802 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2803
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002805 if (ioc->mtrr_reg > 0) {
2806 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002807 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002808 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809#endif
2810
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002811 /* Zap the adapter lookup ptr! */
2812 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002814 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002815 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2816 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002817
2818 if (ioc->alt_ioc)
2819 ioc->alt_ioc->alt_ioc = NULL;
2820
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002821 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822}
2823
2824/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002825/**
2826 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827 * @ioc: Pointer to MPT adapter structure
2828 */
2829static void
2830MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2831{
2832 int i = 0;
2833
2834 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302835 if (ioc->prod_name)
2836 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 printk("Capabilities={");
2838
2839 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2840 printk("Initiator");
2841 i++;
2842 }
2843
2844 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2845 printk("%sTarget", i ? "," : "");
2846 i++;
2847 }
2848
2849 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2850 printk("%sLAN", i ? "," : "");
2851 i++;
2852 }
2853
2854#if 0
2855 /*
2856 * This would probably evoke more questions than it's worth
2857 */
2858 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2859 printk("%sLogBusAddr", i ? "," : "");
2860 i++;
2861 }
2862#endif
2863
2864 printk("}\n");
2865}
2866
2867/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002868/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2870 * @ioc: Pointer to MPT_ADAPTER structure
2871 * @force: Force hard KickStart of IOC
2872 * @sleepFlag: Specifies whether the process can sleep
2873 *
2874 * Returns:
2875 * 1 - DIAG reset and READY
2876 * 0 - READY initially OR soft reset and READY
2877 * -1 - Any failure on KickStart
2878 * -2 - Msg Unit Reset Failed
2879 * -3 - IO Unit Reset Failed
2880 * -4 - IOC owned by a PEER
2881 */
2882static int
2883MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2884{
2885 u32 ioc_state;
2886 int statefault = 0;
2887 int cntdn;
2888 int hard_reset_done = 0;
2889 int r;
2890 int ii;
2891 int whoinit;
2892
2893 /* Get current [raw] IOC state */
2894 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002895 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896
2897 /*
2898 * Check to see if IOC got left/stuck in doorbell handshake
2899 * grip of death. If so, hard reset the IOC.
2900 */
2901 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2902 statefault = 1;
2903 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2904 ioc->name);
2905 }
2906
2907 /* Is it already READY? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302908 if (!statefault &&
2909 ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) {
2910 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2911 "IOC is in READY state\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 return 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302913 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914
2915 /*
2916 * Check to see if IOC is in FAULT state.
2917 */
2918 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2919 statefault = 2;
2920 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002921 ioc->name);
2922 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2923 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 }
2925
2926 /*
2927 * Hmmm... Did it get left operational?
2928 */
2929 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302930 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 ioc->name));
2932
2933 /* Check WhoInit.
2934 * If PCI Peer, exit.
2935 * Else, if no fault conditions are present, issue a MessageUnitReset
2936 * Else, fall through to KickStart case
2937 */
2938 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002939 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2940 "whoinit 0x%x statefault %d force %d\n",
2941 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 if (whoinit == MPI_WHOINIT_PCI_PEER)
2943 return -4;
2944 else {
2945 if ((statefault == 0 ) && (force == 0)) {
2946 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2947 return 0;
2948 }
2949 statefault = 3;
2950 }
2951 }
2952
2953 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2954 if (hard_reset_done < 0)
2955 return -1;
2956
2957 /*
2958 * Loop here waiting for IOC to come READY.
2959 */
2960 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002961 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962
2963 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2964 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2965 /*
2966 * BIOS or previous driver load left IOC in OP state.
2967 * Reset messaging FIFOs.
2968 */
2969 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2970 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2971 return -2;
2972 }
2973 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2974 /*
2975 * Something is wrong. Try to get IOC back
2976 * to a known state.
2977 */
2978 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2979 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2980 return -3;
2981 }
2982 }
2983
2984 ii++; cntdn--;
2985 if (!cntdn) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302986 printk(MYIOC_s_ERR_FMT
2987 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
2988 ioc->name, ioc_state, (int)((ii+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 return -ETIME;
2990 }
2991
2992 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002993 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 } else {
2995 mdelay (1); /* 1 msec delay */
2996 }
2997
2998 }
2999
3000 if (statefault < 3) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303001 printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name,
3002 statefault == 1 ? "stuck handshake" : "IOC FAULT");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 }
3004
3005 return hard_reset_done;
3006}
3007
3008/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003009/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 * mpt_GetIocState - Get the current state of a MPT adapter.
3011 * @ioc: Pointer to MPT_ADAPTER structure
3012 * @cooked: Request raw or cooked IOC state
3013 *
3014 * Returns all IOC Doorbell register bits if cooked==0, else just the
3015 * Doorbell bits in MPI_IOC_STATE_MASK.
3016 */
3017u32
3018mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
3019{
3020 u32 s, sc;
3021
3022 /* Get! */
3023 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 sc = s & MPI_IOC_STATE_MASK;
3025
3026 /* Save! */
3027 ioc->last_state = sc;
3028
3029 return cooked ? sc : s;
3030}
3031
3032/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003033/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 * GetIocFacts - Send IOCFacts request to MPT adapter.
3035 * @ioc: Pointer to MPT_ADAPTER structure
3036 * @sleepFlag: Specifies whether the process can sleep
3037 * @reason: If recovery, only update facts.
3038 *
3039 * Returns 0 for success, non-zero for failure.
3040 */
3041static int
3042GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
3043{
3044 IOCFacts_t get_facts;
3045 IOCFactsReply_t *facts;
3046 int r;
3047 int req_sz;
3048 int reply_sz;
3049 int sz;
3050 u32 status, vv;
3051 u8 shiftFactor=1;
3052
3053 /* IOC *must* NOT be in RESET state! */
3054 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303055 printk(KERN_ERR MYNAM
3056 ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
3057 ioc->name, ioc->last_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 return -44;
3059 }
3060
3061 facts = &ioc->facts;
3062
3063 /* Destination (reply area)... */
3064 reply_sz = sizeof(*facts);
3065 memset(facts, 0, reply_sz);
3066
3067 /* Request area (get_facts on the stack right now!) */
3068 req_sz = sizeof(get_facts);
3069 memset(&get_facts, 0, req_sz);
3070
3071 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
3072 /* Assert: All other get_facts fields are zero! */
3073
Prakash, Sathya436ace72007-07-24 15:42:08 +05303074 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003075 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 ioc->name, req_sz, reply_sz));
3077
3078 /* No non-zero fields in the get_facts request are greater than
3079 * 1 byte in size, so we can just fire it off as is.
3080 */
3081 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3082 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3083 if (r != 0)
3084 return r;
3085
3086 /*
3087 * Now byte swap (GRRR) the necessary fields before any further
3088 * inspection of reply contents.
3089 *
3090 * But need to do some sanity checks on MsgLength (byte) field
3091 * to make sure we don't zero IOC's req_sz!
3092 */
3093 /* Did we get a valid reply? */
3094 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3095 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3096 /*
3097 * If not been here, done that, save off first WhoInit value
3098 */
3099 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3100 ioc->FirstWhoInit = facts->WhoInit;
3101 }
3102
3103 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3104 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3105 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3106 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3107 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003108 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 /* CHECKME! IOCStatus, IOCLogInfo */
3110
3111 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3112 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3113
3114 /*
3115 * FC f/w version changed between 1.1 and 1.2
3116 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3117 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3118 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303119 if (facts->MsgVersion < MPI_VERSION_01_02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 /*
3121 * Handle old FC f/w style, convert to new...
3122 */
3123 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3124 facts->FWVersion.Word =
3125 ((oldv<<12) & 0xFF000000) |
3126 ((oldv<<8) & 0x000FFF00);
3127 } else
3128 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3129
3130 facts->ProductID = le16_to_cpu(facts->ProductID);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303131
Eric Mooreb506ade2007-01-29 09:45:37 -07003132 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3133 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3134 ioc->ir_firmware = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303135
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 facts->CurrentHostMfaHighAddr =
3137 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3138 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3139 facts->CurrentSenseBufferHighAddr =
3140 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3141 facts->CurReplyFrameSize =
3142 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003143 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144
3145 /*
3146 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3147 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3148 * to 14 in MPI-1.01.0x.
3149 */
3150 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
Kashyap, Desai2f187862009-05-29 16:52:37 +05303151 facts->MsgVersion > MPI_VERSION_01_00) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3153 }
3154
3155 sz = facts->FWImageSize;
3156 if ( sz & 0x01 )
3157 sz += 1;
3158 if ( sz & 0x02 )
3159 sz += 2;
3160 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003161
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162 if (!facts->RequestFrameSize) {
3163 /* Something is wrong! */
3164 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3165 ioc->name);
3166 return -55;
3167 }
3168
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003169 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 vv = ((63 / (sz * 4)) + 1) & 0x03;
3171 ioc->NB_for_64_byte_frame = vv;
3172 while ( sz )
3173 {
3174 shiftFactor++;
3175 sz = sz >> 1;
3176 }
3177 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303178 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003179 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3180 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003181
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3183 /*
3184 * Set values for this IOC's request & reply frame sizes,
3185 * and request & reply queue depths...
3186 */
3187 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3188 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3189 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3190 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3191
Prakash, Sathya436ace72007-07-24 15:42:08 +05303192 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303194 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 ioc->name, ioc->req_sz, ioc->req_depth));
3196
3197 /* Get port facts! */
3198 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3199 return r;
3200 }
3201 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003202 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3204 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3205 RequestFrameSize)/sizeof(u32)));
3206 return -66;
3207 }
3208
3209 return 0;
3210}
3211
3212/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003213/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 * GetPortFacts - Send PortFacts request to MPT adapter.
3215 * @ioc: Pointer to MPT_ADAPTER structure
3216 * @portnum: Port number
3217 * @sleepFlag: Specifies whether the process can sleep
3218 *
3219 * Returns 0 for success, non-zero for failure.
3220 */
3221static int
3222GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3223{
3224 PortFacts_t get_pfacts;
3225 PortFactsReply_t *pfacts;
3226 int ii;
3227 int req_sz;
3228 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003229 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230
3231 /* IOC *must* NOT be in RESET state! */
3232 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003233 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3234 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 return -4;
3236 }
3237
3238 pfacts = &ioc->pfacts[portnum];
3239
3240 /* Destination (reply area)... */
3241 reply_sz = sizeof(*pfacts);
3242 memset(pfacts, 0, reply_sz);
3243
3244 /* Request area (get_pfacts on the stack right now!) */
3245 req_sz = sizeof(get_pfacts);
3246 memset(&get_pfacts, 0, req_sz);
3247
3248 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3249 get_pfacts.PortNumber = portnum;
3250 /* Assert: All other get_pfacts fields are zero! */
3251
Prakash, Sathya436ace72007-07-24 15:42:08 +05303252 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 ioc->name, portnum));
3254
3255 /* No non-zero fields in the get_pfacts request are greater than
3256 * 1 byte in size, so we can just fire it off as is.
3257 */
3258 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3259 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3260 if (ii != 0)
3261 return ii;
3262
3263 /* Did we get a valid reply? */
3264
3265 /* Now byte swap the necessary fields in the response. */
3266 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3267 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3268 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3269 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3270 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3271 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3272 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3273 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3274 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3275
Eric Moore793955f2007-01-29 09:42:20 -07003276 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3277 pfacts->MaxDevices;
3278 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3279 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3280
3281 /*
3282 * Place all the devices on channels
3283 *
3284 * (for debuging)
3285 */
3286 if (mpt_channel_mapping) {
3287 ioc->devices_per_bus = 1;
3288 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3289 }
3290
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291 return 0;
3292}
3293
3294/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003295/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 * SendIocInit - Send IOCInit request to MPT adapter.
3297 * @ioc: Pointer to MPT_ADAPTER structure
3298 * @sleepFlag: Specifies whether the process can sleep
3299 *
3300 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3301 *
3302 * Returns 0 for success, non-zero for failure.
3303 */
3304static int
3305SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3306{
3307 IOCInit_t ioc_init;
3308 MPIDefaultReply_t init_reply;
3309 u32 state;
3310 int r;
3311 int count;
3312 int cntdn;
3313
3314 memset(&ioc_init, 0, sizeof(ioc_init));
3315 memset(&init_reply, 0, sizeof(init_reply));
3316
3317 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3318 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3319
3320 /* If we are in a recovery mode and we uploaded the FW image,
3321 * then this pointer is not NULL. Skip the upload a second time.
3322 * Set this flag if cached_fw set for either IOC.
3323 */
3324 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3325 ioc->upload_fw = 1;
3326 else
3327 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303328 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3330
Eric Moore793955f2007-01-29 09:42:20 -07003331 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3332 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303333
Prakash, Sathya436ace72007-07-24 15:42:08 +05303334 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003335 ioc->name, ioc->facts.MsgVersion));
3336 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3337 // set MsgVersion and HeaderVersion host driver was built with
3338 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3339 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003341 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3342 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3343 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3344 return -99;
3345 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3347
Kashyap, Desai2f187862009-05-29 16:52:37 +05303348 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 /* Save the upper 32-bits of the request
3350 * (reply) and sense buffers.
3351 */
3352 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3353 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3354 } else {
3355 /* Force 32-bit addressing */
3356 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3357 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3358 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003359
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3361 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003362 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3363 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364
Prakash, Sathya436ace72007-07-24 15:42:08 +05303365 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 ioc->name, &ioc_init));
3367
3368 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3369 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003370 if (r != 0) {
3371 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003373 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374
3375 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003376 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377 */
3378
Prakash, Sathya436ace72007-07-24 15:42:08 +05303379 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003381
3382 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3383 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386
3387 /* YIKES! SUPER IMPORTANT!!!
3388 * Poll IocState until _OPERATIONAL while IOC is doing
3389 * LoopInit and TargetDiscovery!
3390 */
3391 count = 0;
3392 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3393 state = mpt_GetIocState(ioc, 1);
3394 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3395 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003396 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 } else {
3398 mdelay(1);
3399 }
3400
3401 if (!cntdn) {
3402 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3403 ioc->name, (int)((count+5)/HZ));
3404 return -9;
3405 }
3406
3407 state = mpt_GetIocState(ioc, 1);
3408 count++;
3409 }
Eric Moore29dd3602007-09-14 18:46:51 -06003410 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 ioc->name, count));
3412
Eric Mooreba856d32006-07-11 17:34:01 -06003413 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 return r;
3415}
3416
3417/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003418/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 * SendPortEnable - Send PortEnable request to MPT adapter port.
3420 * @ioc: Pointer to MPT_ADAPTER structure
3421 * @portnum: Port number to enable
3422 * @sleepFlag: Specifies whether the process can sleep
3423 *
3424 * Send PortEnable to bring IOC to OPERATIONAL state.
3425 *
3426 * Returns 0 for success, non-zero for failure.
3427 */
3428static int
3429SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3430{
3431 PortEnable_t port_enable;
3432 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003433 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 int req_sz;
3435 int reply_sz;
3436
3437 /* Destination... */
3438 reply_sz = sizeof(MPIDefaultReply_t);
3439 memset(&reply_buf, 0, reply_sz);
3440
3441 req_sz = sizeof(PortEnable_t);
3442 memset(&port_enable, 0, req_sz);
3443
3444 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3445 port_enable.PortNumber = portnum;
3446/* port_enable.ChainOffset = 0; */
3447/* port_enable.MsgFlags = 0; */
3448/* port_enable.MsgContext = 0; */
3449
Prakash, Sathya436ace72007-07-24 15:42:08 +05303450 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 ioc->name, portnum, &port_enable));
3452
3453 /* RAID FW may take a long time to enable
3454 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003455 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003456 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3457 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3458 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003459 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003460 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3461 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3462 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003464 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465}
3466
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003467/**
3468 * mpt_alloc_fw_memory - allocate firmware memory
3469 * @ioc: Pointer to MPT_ADAPTER structure
3470 * @size: total FW bytes
3471 *
3472 * If memory has already been allocated, the same (cached) value
3473 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303474 *
3475 * Return 0 if successfull, or non-zero for failure
3476 **/
3477int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3479{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303480 int rc;
3481
3482 if (ioc->cached_fw) {
3483 rc = 0; /* use already allocated memory */
3484 goto out;
3485 }
3486 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3488 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303489 rc = 0;
3490 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303492 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3493 if (!ioc->cached_fw) {
3494 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3495 ioc->name);
3496 rc = -1;
3497 } else {
3498 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3499 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3500 ioc->alloc_total += size;
3501 rc = 0;
3502 }
3503 out:
3504 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303506
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003507/**
3508 * mpt_free_fw_memory - free firmware memory
3509 * @ioc: Pointer to MPT_ADAPTER structure
3510 *
3511 * If alt_img is NULL, delete from ioc structure.
3512 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303513 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514void
3515mpt_free_fw_memory(MPT_ADAPTER *ioc)
3516{
3517 int sz;
3518
Prakash, Sathya984621b2008-01-11 14:42:17 +05303519 if (!ioc->cached_fw)
3520 return;
3521
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303523 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3524 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003525 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303526 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528}
3529
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003531/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3533 * @ioc: Pointer to MPT_ADAPTER structure
3534 * @sleepFlag: Specifies whether the process can sleep
3535 *
3536 * Returns 0 for success, >0 for handshake failure
3537 * <0 for fw upload failure.
3538 *
3539 * Remark: If bound IOC and a successful FWUpload was performed
3540 * on the bound IOC, the second image is discarded
3541 * and memory is free'd. Both channels must upload to prevent
3542 * IOC from running in degraded mode.
3543 */
3544static int
3545mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3546{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 u8 reply[sizeof(FWUploadReply_t)];
3548 FWUpload_t *prequest;
3549 FWUploadReply_t *preply;
3550 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551 u32 flagsLength;
3552 int ii, sz, reply_sz;
3553 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303554 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555 /* If the image size is 0, we are done.
3556 */
3557 if ((sz = ioc->facts.FWImageSize) == 0)
3558 return 0;
3559
Prakash, Sathya984621b2008-01-11 14:42:17 +05303560 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3561 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562
Eric Moore29dd3602007-09-14 18:46:51 -06003563 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3564 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003565
Eric Moorebc6e0892007-09-29 10:16:28 -06003566 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3567 kzalloc(ioc->req_sz, GFP_KERNEL);
3568 if (!prequest) {
3569 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3570 "while allocating memory \n", ioc->name));
3571 mpt_free_fw_memory(ioc);
3572 return -ENOMEM;
3573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574
Eric Moorebc6e0892007-09-29 10:16:28 -06003575 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576
3577 reply_sz = sizeof(reply);
3578 memset(preply, 0, reply_sz);
3579
3580 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3581 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3582
3583 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3584 ptcsge->DetailsLength = 12;
3585 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3586 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003587 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303590 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3591 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3592 ioc->SGE_size;
3593 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3594 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3595 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003596 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303598 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3599 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600
Kashyap, Desai2f187862009-05-29 16:52:37 +05303601 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
3602 "rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603
3604 cmdStatus = -EFAULT;
3605 if (ii == 0) {
3606 /* Handshake transfer was complete and successful.
3607 * Check the Reply Frame.
3608 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303609 int status;
3610 status = le16_to_cpu(preply->IOCStatus) &
3611 MPI_IOCSTATUS_MASK;
3612 if (status == MPI_IOCSTATUS_SUCCESS &&
3613 ioc->facts.FWImageSize ==
3614 le32_to_cpu(preply->ActualImageSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 cmdStatus = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303617 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 ioc->name, cmdStatus));
3619
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003620
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 if (cmdStatus) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303622 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
3623 "freeing image \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 mpt_free_fw_memory(ioc);
3625 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003626 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627
3628 return cmdStatus;
3629}
3630
3631/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003632/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 * mpt_downloadboot - DownloadBoot code
3634 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003635 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 * @sleepFlag: Specifies whether the process can sleep
3637 *
3638 * FwDownloadBoot requires Programmed IO access.
3639 *
3640 * Returns 0 for success
3641 * -1 FW Image size is 0
3642 * -2 No valid cached_fw Pointer
3643 * <0 for fw upload failure.
3644 */
3645static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003646mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 MpiExtImageHeader_t *pExtImage;
3649 u32 fwSize;
3650 u32 diag0val;
3651 int count;
3652 u32 *ptrFw;
3653 u32 diagRwData;
3654 u32 nextImage;
3655 u32 load_addr;
3656 u32 ioc_state=0;
3657
Prakash, Sathya436ace72007-07-24 15:42:08 +05303658 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003659 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003660
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3662 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3663 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3664 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3665 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3666 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3667
3668 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3669
3670 /* wait 1 msec */
3671 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003672 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 } else {
3674 mdelay (1);
3675 }
3676
3677 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3678 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3679
3680 for (count = 0; count < 30; count ++) {
3681 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3682 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303683 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 ioc->name, count));
3685 break;
3686 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003687 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003689 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003691 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 }
3693 }
3694
3695 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303696 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003697 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 ioc->name, diag0val));
3699 return -3;
3700 }
3701
3702 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3703 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3704 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3705 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3706 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3707 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3708
3709 /* Set the DiagRwEn and Disable ARM bits */
3710 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3711
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 fwSize = (pFwHeader->ImageSize + 3)/4;
3713 ptrFw = (u32 *) pFwHeader;
3714
3715 /* Write the LoadStartAddress to the DiagRw Address Register
3716 * using Programmed IO
3717 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003718 if (ioc->errata_flag_1064)
3719 pci_enable_io_access(ioc->pcidev);
3720
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303722 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723 ioc->name, pFwHeader->LoadStartAddress));
3724
Prakash, Sathya436ace72007-07-24 15:42:08 +05303725 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726 ioc->name, fwSize*4, ptrFw));
3727 while (fwSize--) {
3728 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3729 }
3730
3731 nextImage = pFwHeader->NextImageHeaderOffset;
3732 while (nextImage) {
3733 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3734
3735 load_addr = pExtImage->LoadStartAddress;
3736
3737 fwSize = (pExtImage->ImageSize + 3) >> 2;
3738 ptrFw = (u32 *)pExtImage;
3739
Prakash, Sathya436ace72007-07-24 15:42:08 +05303740 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 +02003741 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3743
3744 while (fwSize--) {
3745 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3746 }
3747 nextImage = pExtImage->NextImageHeaderOffset;
3748 }
3749
3750 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303751 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3753
3754 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303755 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3757
3758 /* Clear the internal flash bad bit - autoincrementing register,
3759 * so must do two writes.
3760 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003761 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003762 /*
3763 * 1030 and 1035 H/W errata, workaround to access
3764 * the ClearFlashBadSignatureBit
3765 */
3766 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3767 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3768 diagRwData |= 0x40000000;
3769 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3770 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3771
3772 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3773 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3774 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3775 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3776
3777 /* wait 1 msec */
3778 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003779 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003780 } else {
3781 mdelay (1);
3782 }
3783 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003785 if (ioc->errata_flag_1064)
3786 pci_disable_io_access(ioc->pcidev);
3787
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303789 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003790 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003792 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303793 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 ioc->name, diag0val));
3795 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3796
3797 /* Write 0xFF to reset the sequencer */
3798 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3799
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003800 if (ioc->bus_type == SAS) {
3801 ioc_state = mpt_GetIocState(ioc, 0);
3802 if ( (GetIocFacts(ioc, sleepFlag,
3803 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303804 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003805 ioc->name, ioc_state));
3806 return -EFAULT;
3807 }
3808 }
3809
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810 for (count=0; count<HZ*20; count++) {
3811 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303812 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3813 "downloadboot successful! (count=%d) IocState=%x\n",
3814 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003815 if (ioc->bus_type == SAS) {
3816 return 0;
3817 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303819 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3820 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 ioc->name));
3822 return -EFAULT;
3823 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303824 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3825 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826 ioc->name));
3827 return 0;
3828 }
3829 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003830 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 } else {
3832 mdelay (10);
3833 }
3834 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303835 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3836 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837 return -EFAULT;
3838}
3839
3840/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003841/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842 * KickStart - Perform hard reset of MPT adapter.
3843 * @ioc: Pointer to MPT_ADAPTER structure
3844 * @force: Force hard reset
3845 * @sleepFlag: Specifies whether the process can sleep
3846 *
3847 * This routine places MPT adapter in diagnostic mode via the
3848 * WriteSequence register, and then performs a hard reset of adapter
3849 * via the Diagnostic register.
3850 *
3851 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3852 * or NO_SLEEP (interrupt thread, use mdelay)
3853 * force - 1 if doorbell active, board fault state
3854 * board operational, IOC_RECOVERY or
3855 * IOC_BRINGUP and there is an alt_ioc.
3856 * 0 else
3857 *
3858 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003859 * 1 - hard reset, READY
3860 * 0 - no reset due to History bit, READY
3861 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862 * OR reset but failed to come READY
3863 * -2 - no reset, could not enter DIAG mode
3864 * -3 - reset but bad FW bit
3865 */
3866static int
3867KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3868{
3869 int hard_reset_done = 0;
3870 u32 ioc_state=0;
3871 int cnt,cntdn;
3872
Eric Moore29dd3602007-09-14 18:46:51 -06003873 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003874 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875 /* Always issue a Msg Unit Reset first. This will clear some
3876 * SCSI bus hang conditions.
3877 */
3878 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3879
3880 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003881 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882 } else {
3883 mdelay (1000);
3884 }
3885 }
3886
3887 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3888 if (hard_reset_done < 0)
3889 return hard_reset_done;
3890
Prakash, Sathya436ace72007-07-24 15:42:08 +05303891 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003892 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893
3894 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3895 for (cnt=0; cnt<cntdn; cnt++) {
3896 ioc_state = mpt_GetIocState(ioc, 1);
3897 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303898 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 ioc->name, cnt));
3900 return hard_reset_done;
3901 }
3902 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003903 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 } else {
3905 mdelay (10);
3906 }
3907 }
3908
Eric Moore29dd3602007-09-14 18:46:51 -06003909 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3910 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 return -1;
3912}
3913
3914/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003915/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916 * mpt_diag_reset - Perform hard reset of the adapter.
3917 * @ioc: Pointer to MPT_ADAPTER structure
3918 * @ignore: Set if to honor and clear to ignore
3919 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003920 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921 * else set to NO_SLEEP (use mdelay instead)
3922 *
3923 * This routine places the adapter in diagnostic mode via the
3924 * WriteSequence register and then performs a hard reset of adapter
3925 * via the Diagnostic register. Adapter should be in ready state
3926 * upon successful completion.
3927 *
3928 * Returns: 1 hard reset successful
3929 * 0 no reset performed because reset history bit set
3930 * -2 enabling diagnostic mode failed
3931 * -3 diagnostic reset failed
3932 */
3933static int
3934mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3935{
3936 u32 diag0val;
3937 u32 doorbell;
3938 int hard_reset_done = 0;
3939 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303941 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942
Eric Moorecd2c6192007-01-29 09:47:47 -07003943 /* Clear any existing interrupts */
3944 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3945
Eric Moore87cf8982006-06-27 16:09:26 -06003946 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303947
3948 if (!ignore)
3949 return 0;
3950
Prakash, Sathya436ace72007-07-24 15:42:08 +05303951 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003952 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003953 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3954 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3955 if (sleepFlag == CAN_SLEEP)
3956 msleep(1);
3957 else
3958 mdelay(1);
3959
3960 for (count = 0; count < 60; count ++) {
3961 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3962 doorbell &= MPI_IOC_STATE_MASK;
3963
Prakash, Sathya436ace72007-07-24 15:42:08 +05303964 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003965 "looking for READY STATE: doorbell=%x"
3966 " count=%d\n",
3967 ioc->name, doorbell, count));
Kashyap, Desai2f187862009-05-29 16:52:37 +05303968
Eric Moore87cf8982006-06-27 16:09:26 -06003969 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003970 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003971 }
3972
3973 /* wait 1 sec */
3974 if (sleepFlag == CAN_SLEEP)
3975 msleep(1000);
3976 else
3977 mdelay(1000);
3978 }
3979 return -1;
3980 }
3981
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982 /* Use "Diagnostic reset" method! (only thing available!) */
3983 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3984
Prakash, Sathya436ace72007-07-24 15:42:08 +05303985 if (ioc->debug_level & MPT_DEBUG) {
3986 if (ioc->alt_ioc)
3987 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3988 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303990 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991
3992 /* Do the reset if we are told to ignore the reset history
3993 * or if the reset history is 0
3994 */
3995 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3996 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3997 /* Write magic sequence to WriteSequence register
3998 * Loop until in diagnostic mode
3999 */
4000 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4001 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4002 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4003 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4004 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4005 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4006
4007 /* wait 100 msec */
4008 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004009 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 } else {
4011 mdelay (100);
4012 }
4013
4014 count++;
4015 if (count > 20) {
4016 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4017 ioc->name, diag0val);
4018 return -2;
4019
4020 }
4021
4022 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4023
Prakash, Sathya436ace72007-07-24 15:42:08 +05304024 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 ioc->name, diag0val));
4026 }
4027
Prakash, Sathya436ace72007-07-24 15:42:08 +05304028 if (ioc->debug_level & MPT_DEBUG) {
4029 if (ioc->alt_ioc)
4030 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4031 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304033 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 /*
4035 * Disable the ARM (Bug fix)
4036 *
4037 */
4038 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004039 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040
4041 /*
4042 * Now hit the reset bit in the Diagnostic register
4043 * (THE BIG HAMMER!) (Clears DRWE bit).
4044 */
4045 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
4046 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304047 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 ioc->name));
4049
4050 /*
4051 * Call each currently registered protocol IOC reset handler
4052 * with pre-reset indication.
4053 * NOTE: If we're doing _IOC_BRINGUP, there can be no
4054 * MptResetHandlers[] registered yet.
4055 */
4056 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304057 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 int r = 0;
4059
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304060 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
4061 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304062 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4063 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304064 ioc->name, cb_idx));
4065 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304067 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4068 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304069 ioc->name, ioc->alt_ioc->name, cb_idx));
4070 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071 }
4072 }
4073 }
4074 /* FIXME? Examine results here? */
4075 }
4076
Eric Moore0ccdb002006-07-11 17:33:13 -06004077 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304078 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06004079 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304080 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4081 else
4082 cached_fw = NULL;
4083 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084 /* If the DownloadBoot operation fails, the
4085 * IOC will be left unusable. This is a fatal error
4086 * case. _diag_reset will return < 0
4087 */
4088 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304089 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4091 break;
4092 }
4093
Prakash, Sathya436ace72007-07-24 15:42:08 +05304094 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304095 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096 /* wait 1 sec */
4097 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004098 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099 } else {
4100 mdelay (1000);
4101 }
4102 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304103 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004104 printk(MYIOC_s_WARN_FMT
4105 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106 }
4107
4108 } else {
4109 /* Wait for FW to reload and for board
4110 * to go to the READY state.
4111 * Maximum wait is 60 seconds.
4112 * If fail, no error will check again
4113 * with calling program.
4114 */
4115 for (count = 0; count < 60; count ++) {
4116 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4117 doorbell &= MPI_IOC_STATE_MASK;
4118
Kashyap, Desai2f187862009-05-29 16:52:37 +05304119 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4120 "looking for READY STATE: doorbell=%x"
4121 " count=%d\n", ioc->name, doorbell, count));
4122
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123 if (doorbell == MPI_IOC_STATE_READY) {
4124 break;
4125 }
4126
4127 /* wait 1 sec */
4128 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004129 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130 } else {
4131 mdelay (1000);
4132 }
4133 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05304134
4135 if (doorbell != MPI_IOC_STATE_READY)
4136 printk(MYIOC_s_ERR_FMT "Failed to come READY "
4137 "after reset! IocState=%x", ioc->name,
4138 doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139 }
4140 }
4141
4142 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304143 if (ioc->debug_level & MPT_DEBUG) {
4144 if (ioc->alt_ioc)
4145 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4146 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4147 ioc->name, diag0val, diag1val));
4148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149
4150 /* Clear RESET_HISTORY bit! Place board in the
4151 * diagnostic mode to update the diag register.
4152 */
4153 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4154 count = 0;
4155 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4156 /* Write magic sequence to WriteSequence register
4157 * Loop until in diagnostic mode
4158 */
4159 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4160 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4161 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4162 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4163 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4164 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4165
4166 /* wait 100 msec */
4167 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004168 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169 } else {
4170 mdelay (100);
4171 }
4172
4173 count++;
4174 if (count > 20) {
4175 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4176 ioc->name, diag0val);
4177 break;
4178 }
4179 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4180 }
4181 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4182 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4183 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4184 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4185 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4186 ioc->name);
4187 }
4188
4189 /* Disable Diagnostic Mode
4190 */
4191 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4192
4193 /* Check FW reload status flags.
4194 */
4195 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4196 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4197 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4198 ioc->name, diag0val);
4199 return -3;
4200 }
4201
Prakash, Sathya436ace72007-07-24 15:42:08 +05304202 if (ioc->debug_level & MPT_DEBUG) {
4203 if (ioc->alt_ioc)
4204 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4205 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304207 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208
4209 /*
4210 * Reset flag that says we've enabled event notification
4211 */
4212 ioc->facts.EventState = 0;
4213
4214 if (ioc->alt_ioc)
4215 ioc->alt_ioc->facts.EventState = 0;
4216
4217 return hard_reset_done;
4218}
4219
4220/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004221/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222 * SendIocReset - Send IOCReset request to MPT adapter.
4223 * @ioc: Pointer to MPT_ADAPTER structure
4224 * @reset_type: reset type, expected values are
4225 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004226 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 *
4228 * Send IOCReset request to the MPT adapter.
4229 *
4230 * Returns 0 for success, non-zero for failure.
4231 */
4232static int
4233SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4234{
4235 int r;
4236 u32 state;
4237 int cntdn, count;
4238
Prakash, Sathya436ace72007-07-24 15:42:08 +05304239 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 ioc->name, reset_type));
4241 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4242 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4243 return r;
4244
4245 /* FW ACK'd request, wait for READY state
4246 */
4247 count = 0;
4248 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4249
4250 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4251 cntdn--;
4252 count++;
4253 if (!cntdn) {
4254 if (sleepFlag != CAN_SLEEP)
4255 count *= 10;
4256
Kashyap, Desai2f187862009-05-29 16:52:37 +05304257 printk(MYIOC_s_ERR_FMT
4258 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
4259 ioc->name, state, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 return -ETIME;
4261 }
4262
4263 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004264 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265 } else {
4266 mdelay (1); /* 1 msec delay */
4267 }
4268 }
4269
4270 /* TODO!
4271 * Cleanup all event stuff for this IOC; re-issue EventNotification
4272 * request if needed.
4273 */
4274 if (ioc->facts.Function)
4275 ioc->facts.EventState = 0;
4276
4277 return 0;
4278}
4279
4280/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004281/**
4282 * initChainBuffers - Allocate memory for and initialize chain buffers
4283 * @ioc: Pointer to MPT_ADAPTER structure
4284 *
4285 * Allocates memory for and initializes chain buffers,
4286 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 */
4288static int
4289initChainBuffers(MPT_ADAPTER *ioc)
4290{
4291 u8 *mem;
4292 int sz, ii, num_chain;
4293 int scale, num_sge, numSGE;
4294
4295 /* ReqToChain size must equal the req_depth
4296 * index = req_idx
4297 */
4298 if (ioc->ReqToChain == NULL) {
4299 sz = ioc->req_depth * sizeof(int);
4300 mem = kmalloc(sz, GFP_ATOMIC);
4301 if (mem == NULL)
4302 return -1;
4303
4304 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304305 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 ioc->name, mem, sz));
4307 mem = kmalloc(sz, GFP_ATOMIC);
4308 if (mem == NULL)
4309 return -1;
4310
4311 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304312 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 ioc->name, mem, sz));
4314 }
4315 for (ii = 0; ii < ioc->req_depth; ii++) {
4316 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4317 }
4318
4319 /* ChainToChain size must equal the total number
4320 * of chain buffers to be allocated.
4321 * index = chain_idx
4322 *
4323 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004324 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325 *
4326 * num_sge = num sge in request frame + last chain buffer
4327 * scale = num sge per chain buffer if no chain element
4328 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304329 scale = ioc->req_sz / ioc->SGE_size;
4330 if (ioc->sg_addr_size == sizeof(u64))
4331 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304333 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304335 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304337 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304339 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4340 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004341 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304342 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 ioc->name, num_sge, numSGE));
4344
Kashyap, Desai2f187862009-05-29 16:52:37 +05304345 if (ioc->bus_type == FC) {
4346 if (numSGE > MPT_SCSI_FC_SG_DEPTH)
4347 numSGE = MPT_SCSI_FC_SG_DEPTH;
4348 } else {
4349 if (numSGE > MPT_SCSI_SG_DEPTH)
4350 numSGE = MPT_SCSI_SG_DEPTH;
4351 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352
4353 num_chain = 1;
4354 while (numSGE - num_sge > 0) {
4355 num_chain++;
4356 num_sge += (scale - 1);
4357 }
4358 num_chain++;
4359
Prakash, Sathya436ace72007-07-24 15:42:08 +05304360 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 ioc->name, numSGE, num_sge, num_chain));
4362
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004363 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 num_chain *= MPT_SCSI_CAN_QUEUE;
4365 else
4366 num_chain *= MPT_FC_CAN_QUEUE;
4367
4368 ioc->num_chain = num_chain;
4369
4370 sz = num_chain * sizeof(int);
4371 if (ioc->ChainToChain == NULL) {
4372 mem = kmalloc(sz, GFP_ATOMIC);
4373 if (mem == NULL)
4374 return -1;
4375
4376 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304377 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 ioc->name, mem, sz));
4379 } else {
4380 mem = (u8 *) ioc->ChainToChain;
4381 }
4382 memset(mem, 0xFF, sz);
4383 return num_chain;
4384}
4385
4386/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004387/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4389 * @ioc: Pointer to MPT_ADAPTER structure
4390 *
4391 * This routine allocates memory for the MPT reply and request frame
4392 * pools (if necessary), and primes the IOC reply FIFO with
4393 * reply frames.
4394 *
4395 * Returns 0 for success, non-zero for failure.
4396 */
4397static int
4398PrimeIocFifos(MPT_ADAPTER *ioc)
4399{
4400 MPT_FRAME_HDR *mf;
4401 unsigned long flags;
4402 dma_addr_t alloc_dma;
4403 u8 *mem;
4404 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304405 u64 dma_mask;
4406
4407 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408
4409 /* Prime reply FIFO... */
4410
4411 if (ioc->reply_frames == NULL) {
4412 if ( (num_chain = initChainBuffers(ioc)) < 0)
4413 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304414 /*
4415 * 1078 errata workaround for the 36GB limitation
4416 */
4417 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
4418 ioc->dma_mask > DMA_35BIT_MASK) {
4419 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4420 && !pci_set_consistent_dma_mask(ioc->pcidev,
4421 DMA_BIT_MASK(32))) {
4422 dma_mask = DMA_35BIT_MASK;
4423 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4424 "setting 35 bit addressing for "
4425 "Request/Reply/Chain and Sense Buffers\n",
4426 ioc->name));
4427 } else {
4428 /*Reseting DMA mask to 64 bit*/
4429 pci_set_dma_mask(ioc->pcidev,
4430 DMA_BIT_MASK(64));
4431 pci_set_consistent_dma_mask(ioc->pcidev,
4432 DMA_BIT_MASK(64));
4433
4434 printk(MYIOC_s_ERR_FMT
4435 "failed setting 35 bit addressing for "
4436 "Request/Reply/Chain and Sense Buffers\n",
4437 ioc->name);
4438 return -1;
4439 }
4440 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441
4442 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304443 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304445 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 ioc->name, reply_sz, reply_sz));
4447
4448 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304449 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304451 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452 ioc->name, sz, sz));
4453 total_size += sz;
4454
4455 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304456 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304458 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459 ioc->name, sz, sz, num_chain));
4460
4461 total_size += sz;
4462 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4463 if (mem == NULL) {
4464 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4465 ioc->name);
4466 goto out_fail;
4467 }
4468
Prakash, Sathya436ace72007-07-24 15:42:08 +05304469 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4471
4472 memset(mem, 0, total_size);
4473 ioc->alloc_total += total_size;
4474 ioc->alloc = mem;
4475 ioc->alloc_dma = alloc_dma;
4476 ioc->alloc_sz = total_size;
4477 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4478 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4479
Prakash, Sathya436ace72007-07-24 15:42:08 +05304480 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004481 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4482
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 alloc_dma += reply_sz;
4484 mem += reply_sz;
4485
4486 /* Request FIFO - WE manage this! */
4487
4488 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4489 ioc->req_frames_dma = alloc_dma;
4490
Prakash, Sathya436ace72007-07-24 15:42:08 +05304491 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 ioc->name, mem, (void *)(ulong)alloc_dma));
4493
4494 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4495
4496#if defined(CONFIG_MTRR) && 0
4497 /*
4498 * Enable Write Combining MTRR for IOC's memory region.
4499 * (at least as much as we can; "size and base must be
4500 * multiples of 4 kiB"
4501 */
4502 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4503 sz,
4504 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304505 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 ioc->name, ioc->req_frames_dma, sz));
4507#endif
4508
4509 for (i = 0; i < ioc->req_depth; i++) {
4510 alloc_dma += ioc->req_sz;
4511 mem += ioc->req_sz;
4512 }
4513
4514 ioc->ChainBuffer = mem;
4515 ioc->ChainBufferDMA = alloc_dma;
4516
Prakash, Sathya436ace72007-07-24 15:42:08 +05304517 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4519
4520 /* Initialize the free chain Q.
4521 */
4522
4523 INIT_LIST_HEAD(&ioc->FreeChainQ);
4524
4525 /* Post the chain buffers to the FreeChainQ.
4526 */
4527 mem = (u8 *)ioc->ChainBuffer;
4528 for (i=0; i < num_chain; i++) {
4529 mf = (MPT_FRAME_HDR *) mem;
4530 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4531 mem += ioc->req_sz;
4532 }
4533
4534 /* Initialize Request frames linked list
4535 */
4536 alloc_dma = ioc->req_frames_dma;
4537 mem = (u8 *) ioc->req_frames;
4538
4539 spin_lock_irqsave(&ioc->FreeQlock, flags);
4540 INIT_LIST_HEAD(&ioc->FreeQ);
4541 for (i = 0; i < ioc->req_depth; i++) {
4542 mf = (MPT_FRAME_HDR *) mem;
4543
4544 /* Queue REQUESTs *internally*! */
4545 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4546
4547 mem += ioc->req_sz;
4548 }
4549 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4550
4551 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4552 ioc->sense_buf_pool =
4553 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4554 if (ioc->sense_buf_pool == NULL) {
4555 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4556 ioc->name);
4557 goto out_fail;
4558 }
4559
4560 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4561 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304562 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4564
4565 }
4566
4567 /* Post Reply frames to FIFO
4568 */
4569 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304570 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4572
4573 for (i = 0; i < ioc->reply_depth; i++) {
4574 /* Write each address to the IOC! */
4575 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4576 alloc_dma += ioc->reply_sz;
4577 }
4578
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304579 if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
4580 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4581 ioc->dma_mask))
4582 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4583 "restoring 64 bit addressing\n", ioc->name));
4584
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585 return 0;
4586
4587out_fail:
Kashyap, Desai2f187862009-05-29 16:52:37 +05304588
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 if (ioc->alloc != NULL) {
4590 sz = ioc->alloc_sz;
4591 pci_free_consistent(ioc->pcidev,
4592 sz,
4593 ioc->alloc, ioc->alloc_dma);
4594 ioc->reply_frames = NULL;
4595 ioc->req_frames = NULL;
4596 ioc->alloc_total -= sz;
4597 }
4598 if (ioc->sense_buf_pool != NULL) {
4599 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4600 pci_free_consistent(ioc->pcidev,
4601 sz,
4602 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4603 ioc->sense_buf_pool = NULL;
4604 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304605
4606 if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
4607 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4608 DMA_BIT_MASK(64)))
4609 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4610 "restoring 64 bit addressing\n", ioc->name));
4611
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 return -1;
4613}
4614
4615/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4616/**
4617 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4618 * from IOC via doorbell handshake method.
4619 * @ioc: Pointer to MPT_ADAPTER structure
4620 * @reqBytes: Size of the request in bytes
4621 * @req: Pointer to MPT request frame
4622 * @replyBytes: Expected size of the reply in bytes
4623 * @u16reply: Pointer to area where reply should be written
4624 * @maxwait: Max wait time for a reply (in seconds)
4625 * @sleepFlag: Specifies whether the process can sleep
4626 *
4627 * NOTES: It is the callers responsibility to byte-swap fields in the
4628 * request which are greater than 1 byte in size. It is also the
4629 * callers responsibility to byte-swap response fields which are
4630 * greater than 1 byte in size.
4631 *
4632 * Returns 0 for success, non-zero for failure.
4633 */
4634static int
4635mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004636 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637{
4638 MPIDefaultReply_t *mptReply;
4639 int failcnt = 0;
4640 int t;
4641
4642 /*
4643 * Get ready to cache a handshake reply
4644 */
4645 ioc->hs_reply_idx = 0;
4646 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4647 mptReply->MsgLength = 0;
4648
4649 /*
4650 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4651 * then tell IOC that we want to handshake a request of N words.
4652 * (WRITE u32val to Doorbell reg).
4653 */
4654 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4655 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4656 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4657 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4658
4659 /*
4660 * Wait for IOC's doorbell handshake int
4661 */
4662 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4663 failcnt++;
4664
Prakash, Sathya436ace72007-07-24 15:42:08 +05304665 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4667
4668 /* Read doorbell and check for active bit */
4669 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4670 return -1;
4671
4672 /*
4673 * Clear doorbell int (WRITE 0 to IntStatus reg),
4674 * then wait for IOC to ACKnowledge that it's ready for
4675 * our handshake request.
4676 */
4677 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4678 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4679 failcnt++;
4680
4681 if (!failcnt) {
4682 int ii;
4683 u8 *req_as_bytes = (u8 *) req;
4684
4685 /*
4686 * Stuff request words via doorbell handshake,
4687 * with ACK from IOC for each.
4688 */
4689 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4690 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4691 (req_as_bytes[(ii*4) + 1] << 8) |
4692 (req_as_bytes[(ii*4) + 2] << 16) |
4693 (req_as_bytes[(ii*4) + 3] << 24));
4694
4695 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4696 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4697 failcnt++;
4698 }
4699
Prakash, Sathya436ace72007-07-24 15:42:08 +05304700 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004701 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702
Prakash, Sathya436ace72007-07-24 15:42:08 +05304703 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4705
4706 /*
4707 * Wait for completion of doorbell handshake reply from the IOC
4708 */
4709 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4710 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004711
Prakash, Sathya436ace72007-07-24 15:42:08 +05304712 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4714
4715 /*
4716 * Copy out the cached reply...
4717 */
4718 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4719 u16reply[ii] = ioc->hs_reply[ii];
4720 } else {
4721 return -99;
4722 }
4723
4724 return -failcnt;
4725}
4726
4727/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004728/**
4729 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730 * @ioc: Pointer to MPT_ADAPTER structure
4731 * @howlong: How long to wait (in seconds)
4732 * @sleepFlag: Specifies whether the process can sleep
4733 *
4734 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004735 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4736 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737 *
4738 * Returns a negative value on failure, else wait loop count.
4739 */
4740static int
4741WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4742{
4743 int cntdn;
4744 int count = 0;
4745 u32 intstat=0;
4746
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004747 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748
4749 if (sleepFlag == CAN_SLEEP) {
4750 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004751 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4753 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4754 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 count++;
4756 }
4757 } else {
4758 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004759 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4761 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4762 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 count++;
4764 }
4765 }
4766
4767 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304768 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 ioc->name, count));
4770 return count;
4771 }
4772
4773 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4774 ioc->name, count, intstat);
4775 return -1;
4776}
4777
4778/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004779/**
4780 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 * @ioc: Pointer to MPT_ADAPTER structure
4782 * @howlong: How long to wait (in seconds)
4783 * @sleepFlag: Specifies whether the process can sleep
4784 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004785 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4786 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004787 *
4788 * Returns a negative value on failure, else wait loop count.
4789 */
4790static int
4791WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4792{
4793 int cntdn;
4794 int count = 0;
4795 u32 intstat=0;
4796
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004797 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798 if (sleepFlag == CAN_SLEEP) {
4799 while (--cntdn) {
4800 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4801 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4802 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004803 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804 count++;
4805 }
4806 } else {
4807 while (--cntdn) {
4808 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4809 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4810 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004811 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 count++;
4813 }
4814 }
4815
4816 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304817 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 ioc->name, count, howlong));
4819 return count;
4820 }
4821
4822 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4823 ioc->name, count, intstat);
4824 return -1;
4825}
4826
4827/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004828/**
4829 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830 * @ioc: Pointer to MPT_ADAPTER structure
4831 * @howlong: How long to wait (in seconds)
4832 * @sleepFlag: Specifies whether the process can sleep
4833 *
4834 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4835 * Reply is cached to IOC private area large enough to hold a maximum
4836 * of 128 bytes of reply data.
4837 *
4838 * Returns a negative value on failure, else size of reply in WORDS.
4839 */
4840static int
4841WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4842{
4843 int u16cnt = 0;
4844 int failcnt = 0;
4845 int t;
4846 u16 *hs_reply = ioc->hs_reply;
4847 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4848 u16 hword;
4849
4850 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4851
4852 /*
4853 * Get first two u16's so we can look at IOC's intended reply MsgLength
4854 */
4855 u16cnt=0;
4856 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4857 failcnt++;
4858 } else {
4859 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4860 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4861 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4862 failcnt++;
4863 else {
4864 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4865 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4866 }
4867 }
4868
Prakash, Sathya436ace72007-07-24 15:42:08 +05304869 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004870 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4872
4873 /*
4874 * If no error (and IOC said MsgLength is > 0), piece together
4875 * reply 16 bits at a time.
4876 */
4877 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4878 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4879 failcnt++;
4880 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4881 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004882 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 hs_reply[u16cnt] = hword;
4884 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4885 }
4886
4887 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4888 failcnt++;
4889 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4890
4891 if (failcnt) {
4892 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4893 ioc->name);
4894 return -failcnt;
4895 }
4896#if 0
4897 else if (u16cnt != (2 * mptReply->MsgLength)) {
4898 return -101;
4899 }
4900 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4901 return -102;
4902 }
4903#endif
4904
Prakash, Sathya436ace72007-07-24 15:42:08 +05304905 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004906 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004907
Prakash, Sathya436ace72007-07-24 15:42:08 +05304908 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909 ioc->name, t, u16cnt/2));
4910 return u16cnt/2;
4911}
4912
4913/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004914/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915 * GetLanConfigPages - Fetch LANConfig pages.
4916 * @ioc: Pointer to MPT_ADAPTER structure
4917 *
4918 * Return: 0 for success
4919 * -ENOMEM if no memory available
4920 * -EPERM if not allowed due to ISR context
4921 * -EAGAIN if no msg frames currently available
4922 * -EFAULT for non-successful reply or no reply (timeout)
4923 */
4924static int
4925GetLanConfigPages(MPT_ADAPTER *ioc)
4926{
4927 ConfigPageHeader_t hdr;
4928 CONFIGPARMS cfg;
4929 LANPage0_t *ppage0_alloc;
4930 dma_addr_t page0_dma;
4931 LANPage1_t *ppage1_alloc;
4932 dma_addr_t page1_dma;
4933 int rc = 0;
4934 int data_sz;
4935 int copy_sz;
4936
4937 /* Get LAN Page 0 header */
4938 hdr.PageVersion = 0;
4939 hdr.PageLength = 0;
4940 hdr.PageNumber = 0;
4941 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004942 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943 cfg.physAddr = -1;
4944 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4945 cfg.dir = 0;
4946 cfg.pageAddr = 0;
4947 cfg.timeout = 0;
4948
4949 if ((rc = mpt_config(ioc, &cfg)) != 0)
4950 return rc;
4951
4952 if (hdr.PageLength > 0) {
4953 data_sz = hdr.PageLength * 4;
4954 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4955 rc = -ENOMEM;
4956 if (ppage0_alloc) {
4957 memset((u8 *)ppage0_alloc, 0, data_sz);
4958 cfg.physAddr = page0_dma;
4959 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4960
4961 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4962 /* save the data */
4963 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4964 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4965
4966 }
4967
4968 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4969
4970 /* FIXME!
4971 * Normalize endianness of structure data,
4972 * by byte-swapping all > 1 byte fields!
4973 */
4974
4975 }
4976
4977 if (rc)
4978 return rc;
4979 }
4980
4981 /* Get LAN Page 1 header */
4982 hdr.PageVersion = 0;
4983 hdr.PageLength = 0;
4984 hdr.PageNumber = 1;
4985 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004986 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987 cfg.physAddr = -1;
4988 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4989 cfg.dir = 0;
4990 cfg.pageAddr = 0;
4991
4992 if ((rc = mpt_config(ioc, &cfg)) != 0)
4993 return rc;
4994
4995 if (hdr.PageLength == 0)
4996 return 0;
4997
4998 data_sz = hdr.PageLength * 4;
4999 rc = -ENOMEM;
5000 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
5001 if (ppage1_alloc) {
5002 memset((u8 *)ppage1_alloc, 0, data_sz);
5003 cfg.physAddr = page1_dma;
5004 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5005
5006 if ((rc = mpt_config(ioc, &cfg)) == 0) {
5007 /* save the data */
5008 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
5009 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
5010 }
5011
5012 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
5013
5014 /* FIXME!
5015 * Normalize endianness of structure data,
5016 * by byte-swapping all > 1 byte fields!
5017 */
5018
5019 }
5020
5021 return rc;
5022}
5023
5024/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005025/**
5026 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005027 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005028 * @persist_opcode: see below
5029 *
5030 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
5031 * devices not currently present.
5032 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
5033 *
5034 * NOTE: Don't use not this function during interrupt time.
5035 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005036 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005037 */
5038
5039/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5040int
5041mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
5042{
5043 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
5044 SasIoUnitControlReply_t *sasIoUnitCntrReply;
5045 MPT_FRAME_HDR *mf = NULL;
5046 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305047 int ret = 0;
5048 unsigned long timeleft;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005049
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305050 mutex_lock(&ioc->mptbase_cmds.mutex);
5051
5052 /* init the internal cmd struct */
5053 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
5054 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005055
5056 /* insure garbage is not sent to fw */
5057 switch(persist_opcode) {
5058
5059 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
5060 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
5061 break;
5062
5063 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305064 ret = -1;
5065 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005066 }
5067
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305068 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
5069 __func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005070
5071 /* Get a MF for this command.
5072 */
5073 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305074 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
5075 ret = -1;
5076 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005077 }
5078
5079 mpi_hdr = (MPIHeader_t *) mf;
5080 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
5081 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
5082 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
5083 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
5084 sasIoUnitCntrReq->Operation = persist_opcode;
5085
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005086 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305087 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
5088 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
5089 ret = -ETIME;
5090 printk(KERN_DEBUG "%s: failed\n", __func__);
5091 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
5092 goto out;
5093 if (!timeleft) {
5094 printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n",
5095 ioc->name, __func__);
5096 mpt_HardResetHandler(ioc, CAN_SLEEP);
5097 mpt_free_msg_frame(ioc, mf);
5098 }
5099 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005100 }
5101
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305102 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
5103 ret = -1;
5104 goto out;
5105 }
5106
5107 sasIoUnitCntrReply =
5108 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5109 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5110 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5111 __func__, sasIoUnitCntrReply->IOCStatus,
5112 sasIoUnitCntrReply->IOCLogInfo);
5113 printk(KERN_DEBUG "%s: failed\n", __func__);
5114 ret = -1;
5115 } else
5116 printk(KERN_DEBUG "%s: success\n", __func__);
5117 out:
5118
5119 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5120 mutex_unlock(&ioc->mptbase_cmds.mutex);
5121 return ret;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005122}
5123
5124/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005125
5126static void
5127mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5128 MpiEventDataRaid_t * pRaidEventData)
5129{
5130 int volume;
5131 int reason;
5132 int disk;
5133 int status;
5134 int flags;
5135 int state;
5136
5137 volume = pRaidEventData->VolumeID;
5138 reason = pRaidEventData->ReasonCode;
5139 disk = pRaidEventData->PhysDiskNum;
5140 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5141 flags = (status >> 0) & 0xff;
5142 state = (status >> 8) & 0xff;
5143
5144 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5145 return;
5146 }
5147
5148 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5149 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5150 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005151 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5152 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005153 } else {
5154 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5155 ioc->name, volume);
5156 }
5157
5158 switch(reason) {
5159 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5160 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5161 ioc->name);
5162 break;
5163
5164 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5165
5166 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5167 ioc->name);
5168 break;
5169
5170 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5171 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5172 ioc->name);
5173 break;
5174
5175 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5176 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5177 ioc->name,
5178 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5179 ? "optimal"
5180 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5181 ? "degraded"
5182 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5183 ? "failed"
5184 : "state unknown",
5185 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5186 ? ", enabled" : "",
5187 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5188 ? ", quiesced" : "",
5189 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5190 ? ", resync in progress" : "" );
5191 break;
5192
5193 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5194 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5195 ioc->name, disk);
5196 break;
5197
5198 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5199 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5200 ioc->name);
5201 break;
5202
5203 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5204 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5205 ioc->name);
5206 break;
5207
5208 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5209 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5210 ioc->name);
5211 break;
5212
5213 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5214 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5215 ioc->name,
5216 state == MPI_PHYSDISK0_STATUS_ONLINE
5217 ? "online"
5218 : state == MPI_PHYSDISK0_STATUS_MISSING
5219 ? "missing"
5220 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5221 ? "not compatible"
5222 : state == MPI_PHYSDISK0_STATUS_FAILED
5223 ? "failed"
5224 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5225 ? "initializing"
5226 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5227 ? "offline requested"
5228 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5229 ? "failed requested"
5230 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5231 ? "offline"
5232 : "state unknown",
5233 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5234 ? ", out of sync" : "",
5235 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5236 ? ", quiesced" : "" );
5237 break;
5238
5239 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5240 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5241 ioc->name, disk);
5242 break;
5243
5244 case MPI_EVENT_RAID_RC_SMART_DATA:
5245 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5246 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5247 break;
5248
5249 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5250 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5251 ioc->name, disk);
5252 break;
5253 }
5254}
5255
5256/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005257/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005258 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5259 * @ioc: Pointer to MPT_ADAPTER structure
5260 *
5261 * Returns: 0 for success
5262 * -ENOMEM if no memory available
5263 * -EPERM if not allowed due to ISR context
5264 * -EAGAIN if no msg frames currently available
5265 * -EFAULT for non-successful reply or no reply (timeout)
5266 */
5267static int
5268GetIoUnitPage2(MPT_ADAPTER *ioc)
5269{
5270 ConfigPageHeader_t hdr;
5271 CONFIGPARMS cfg;
5272 IOUnitPage2_t *ppage_alloc;
5273 dma_addr_t page_dma;
5274 int data_sz;
5275 int rc;
5276
5277 /* Get the page header */
5278 hdr.PageVersion = 0;
5279 hdr.PageLength = 0;
5280 hdr.PageNumber = 2;
5281 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005282 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283 cfg.physAddr = -1;
5284 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5285 cfg.dir = 0;
5286 cfg.pageAddr = 0;
5287 cfg.timeout = 0;
5288
5289 if ((rc = mpt_config(ioc, &cfg)) != 0)
5290 return rc;
5291
5292 if (hdr.PageLength == 0)
5293 return 0;
5294
5295 /* Read the config page */
5296 data_sz = hdr.PageLength * 4;
5297 rc = -ENOMEM;
5298 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5299 if (ppage_alloc) {
5300 memset((u8 *)ppage_alloc, 0, data_sz);
5301 cfg.physAddr = page_dma;
5302 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5303
5304 /* If Good, save data */
5305 if ((rc = mpt_config(ioc, &cfg)) == 0)
5306 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5307
5308 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5309 }
5310
5311 return rc;
5312}
5313
5314/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005315/**
5316 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005317 * @ioc: Pointer to a Adapter Strucutre
5318 * @portnum: IOC port number
5319 *
5320 * Return: -EFAULT if read of config page header fails
5321 * or if no nvram
5322 * If read of SCSI Port Page 0 fails,
5323 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5324 * Adapter settings: async, narrow
5325 * Return 1
5326 * If read of SCSI Port Page 2 fails,
5327 * Adapter settings valid
5328 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5329 * Return 1
5330 * Else
5331 * Both valid
5332 * Return 0
5333 * CHECK - what type of locking mechanisms should be used????
5334 */
5335static int
5336mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5337{
5338 u8 *pbuf;
5339 dma_addr_t buf_dma;
5340 CONFIGPARMS cfg;
5341 ConfigPageHeader_t header;
5342 int ii;
5343 int data, rc = 0;
5344
5345 /* Allocate memory
5346 */
5347 if (!ioc->spi_data.nvram) {
5348 int sz;
5349 u8 *mem;
5350 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5351 mem = kmalloc(sz, GFP_ATOMIC);
5352 if (mem == NULL)
5353 return -EFAULT;
5354
5355 ioc->spi_data.nvram = (int *) mem;
5356
Prakash, Sathya436ace72007-07-24 15:42:08 +05305357 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358 ioc->name, ioc->spi_data.nvram, sz));
5359 }
5360
5361 /* Invalidate NVRAM information
5362 */
5363 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5364 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5365 }
5366
5367 /* Read SPP0 header, allocate memory, then read page.
5368 */
5369 header.PageVersion = 0;
5370 header.PageLength = 0;
5371 header.PageNumber = 0;
5372 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005373 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005374 cfg.physAddr = -1;
5375 cfg.pageAddr = portnum;
5376 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5377 cfg.dir = 0;
5378 cfg.timeout = 0; /* use default */
5379 if (mpt_config(ioc, &cfg) != 0)
5380 return -EFAULT;
5381
5382 if (header.PageLength > 0) {
5383 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5384 if (pbuf) {
5385 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5386 cfg.physAddr = buf_dma;
5387 if (mpt_config(ioc, &cfg) != 0) {
5388 ioc->spi_data.maxBusWidth = MPT_NARROW;
5389 ioc->spi_data.maxSyncOffset = 0;
5390 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5391 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5392 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305393 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5394 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005395 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396 } else {
5397 /* Save the Port Page 0 data
5398 */
5399 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5400 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5401 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5402
5403 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5404 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005405 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5406 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 ioc->name, pPP0->Capabilities));
5408 }
5409 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5410 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5411 if (data) {
5412 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5413 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5414 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305415 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5416 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005417 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418 } else {
5419 ioc->spi_data.maxSyncOffset = 0;
5420 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5421 }
5422
5423 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5424
5425 /* Update the minSyncFactor based on bus type.
5426 */
5427 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5428 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5429
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005430 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305432 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5433 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005434 ioc->name, ioc->spi_data.minSyncFactor));
5435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436 }
5437 }
5438 if (pbuf) {
5439 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5440 }
5441 }
5442 }
5443
5444 /* SCSI Port Page 2 - Read the header then the page.
5445 */
5446 header.PageVersion = 0;
5447 header.PageLength = 0;
5448 header.PageNumber = 2;
5449 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005450 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451 cfg.physAddr = -1;
5452 cfg.pageAddr = portnum;
5453 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5454 cfg.dir = 0;
5455 if (mpt_config(ioc, &cfg) != 0)
5456 return -EFAULT;
5457
5458 if (header.PageLength > 0) {
5459 /* Allocate memory and read SCSI Port Page 2
5460 */
5461 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5462 if (pbuf) {
5463 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5464 cfg.physAddr = buf_dma;
5465 if (mpt_config(ioc, &cfg) != 0) {
5466 /* Nvram data is left with INVALID mark
5467 */
5468 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005469 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5470
5471 /* This is an ATTO adapter, read Page2 accordingly
5472 */
5473 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5474 ATTODeviceInfo_t *pdevice = NULL;
5475 u16 ATTOFlags;
5476
5477 /* Save the Port Page 2 data
5478 * (reformat into a 32bit quantity)
5479 */
5480 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5481 pdevice = &pPP2->DeviceSettings[ii];
5482 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5483 data = 0;
5484
5485 /* Translate ATTO device flags to LSI format
5486 */
5487 if (ATTOFlags & ATTOFLAG_DISC)
5488 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5489 if (ATTOFlags & ATTOFLAG_ID_ENB)
5490 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5491 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5492 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5493 if (ATTOFlags & ATTOFLAG_TAGGED)
5494 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5495 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5496 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5497
5498 data = (data << 16) | (pdevice->Period << 8) | 10;
5499 ioc->spi_data.nvram[ii] = data;
5500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501 } else {
5502 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5503 MpiDeviceInfo_t *pdevice = NULL;
5504
Moore, Ericd8e925d2006-01-16 18:53:06 -07005505 /*
5506 * Save "Set to Avoid SCSI Bus Resets" flag
5507 */
5508 ioc->spi_data.bus_reset =
5509 (le32_to_cpu(pPP2->PortFlags) &
5510 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5511 0 : 1 ;
5512
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 /* Save the Port Page 2 data
5514 * (reformat into a 32bit quantity)
5515 */
5516 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5517 ioc->spi_data.PortFlags = data;
5518 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5519 pdevice = &pPP2->DeviceSettings[ii];
5520 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5521 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5522 ioc->spi_data.nvram[ii] = data;
5523 }
5524 }
5525
5526 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5527 }
5528 }
5529
5530 /* Update Adapter limits with those from NVRAM
5531 * Comment: Don't need to do this. Target performance
5532 * parameters will never exceed the adapters limits.
5533 */
5534
5535 return rc;
5536}
5537
5538/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005539/**
5540 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541 * @ioc: Pointer to a Adapter Strucutre
5542 * @portnum: IOC port number
5543 *
5544 * Return: -EFAULT if read of config page header fails
5545 * or 0 if success.
5546 */
5547static int
5548mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5549{
5550 CONFIGPARMS cfg;
5551 ConfigPageHeader_t header;
5552
5553 /* Read the SCSI Device Page 1 header
5554 */
5555 header.PageVersion = 0;
5556 header.PageLength = 0;
5557 header.PageNumber = 1;
5558 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005559 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005560 cfg.physAddr = -1;
5561 cfg.pageAddr = portnum;
5562 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5563 cfg.dir = 0;
5564 cfg.timeout = 0;
5565 if (mpt_config(ioc, &cfg) != 0)
5566 return -EFAULT;
5567
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005568 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5569 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570
5571 header.PageVersion = 0;
5572 header.PageLength = 0;
5573 header.PageNumber = 0;
5574 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5575 if (mpt_config(ioc, &cfg) != 0)
5576 return -EFAULT;
5577
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005578 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5579 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580
Prakash, Sathya436ace72007-07-24 15:42:08 +05305581 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5583
Prakash, Sathya436ace72007-07-24 15:42:08 +05305584 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5586 return 0;
5587}
5588
Eric Mooreb506ade2007-01-29 09:45:37 -07005589/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005590 * mpt_inactive_raid_list_free - This clears this link list.
5591 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005592 **/
5593static void
5594mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5595{
5596 struct inactive_raid_component_info *component_info, *pNext;
5597
5598 if (list_empty(&ioc->raid_data.inactive_list))
5599 return;
5600
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005601 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005602 list_for_each_entry_safe(component_info, pNext,
5603 &ioc->raid_data.inactive_list, list) {
5604 list_del(&component_info->list);
5605 kfree(component_info);
5606 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005607 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005608}
5609
5610/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005611 * 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 -07005612 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005613 * @ioc : pointer to per adapter structure
5614 * @channel : volume channel
5615 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005616 **/
5617static void
5618mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5619{
5620 CONFIGPARMS cfg;
5621 ConfigPageHeader_t hdr;
5622 dma_addr_t dma_handle;
5623 pRaidVolumePage0_t buffer = NULL;
5624 int i;
5625 RaidPhysDiskPage0_t phys_disk;
5626 struct inactive_raid_component_info *component_info;
5627 int handle_inactive_volumes;
5628
5629 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5630 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5631 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5632 cfg.pageAddr = (channel << 8) + id;
5633 cfg.cfghdr.hdr = &hdr;
5634 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5635
5636 if (mpt_config(ioc, &cfg) != 0)
5637 goto out;
5638
5639 if (!hdr.PageLength)
5640 goto out;
5641
5642 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5643 &dma_handle);
5644
5645 if (!buffer)
5646 goto out;
5647
5648 cfg.physAddr = dma_handle;
5649 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5650
5651 if (mpt_config(ioc, &cfg) != 0)
5652 goto out;
5653
5654 if (!buffer->NumPhysDisks)
5655 goto out;
5656
5657 handle_inactive_volumes =
5658 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5659 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5660 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5661 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5662
5663 if (!handle_inactive_volumes)
5664 goto out;
5665
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005666 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005667 for (i = 0; i < buffer->NumPhysDisks; i++) {
5668 if(mpt_raid_phys_disk_pg0(ioc,
5669 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5670 continue;
5671
5672 if ((component_info = kmalloc(sizeof (*component_info),
5673 GFP_KERNEL)) == NULL)
5674 continue;
5675
5676 component_info->volumeID = id;
5677 component_info->volumeBus = channel;
5678 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5679 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5680 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5681 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5682
5683 list_add_tail(&component_info->list,
5684 &ioc->raid_data.inactive_list);
5685 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005686 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005687
5688 out:
5689 if (buffer)
5690 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5691 dma_handle);
5692}
5693
5694/**
5695 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5696 * @ioc: Pointer to a Adapter Structure
5697 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5698 * @phys_disk: requested payload data returned
5699 *
5700 * Return:
5701 * 0 on success
5702 * -EFAULT if read of config page header fails or data pointer not NULL
5703 * -ENOMEM if pci_alloc failed
5704 **/
5705int
Kashyap, Desai2f187862009-05-29 16:52:37 +05305706mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
5707 RaidPhysDiskPage0_t *phys_disk)
Eric Mooreb506ade2007-01-29 09:45:37 -07005708{
Kashyap, Desai2f187862009-05-29 16:52:37 +05305709 CONFIGPARMS cfg;
5710 ConfigPageHeader_t hdr;
Eric Mooreb506ade2007-01-29 09:45:37 -07005711 dma_addr_t dma_handle;
5712 pRaidPhysDiskPage0_t buffer = NULL;
5713 int rc;
5714
5715 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5716 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
Kashyap, Desai2f187862009-05-29 16:52:37 +05305717 memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
Eric Mooreb506ade2007-01-29 09:45:37 -07005718
Kashyap, Desai2f187862009-05-29 16:52:37 +05305719 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
Eric Mooreb506ade2007-01-29 09:45:37 -07005720 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5721 cfg.cfghdr.hdr = &hdr;
5722 cfg.physAddr = -1;
5723 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5724
5725 if (mpt_config(ioc, &cfg) != 0) {
5726 rc = -EFAULT;
5727 goto out;
5728 }
5729
5730 if (!hdr.PageLength) {
5731 rc = -EFAULT;
5732 goto out;
5733 }
5734
5735 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5736 &dma_handle);
5737
5738 if (!buffer) {
5739 rc = -ENOMEM;
5740 goto out;
5741 }
5742
5743 cfg.physAddr = dma_handle;
5744 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5745 cfg.pageAddr = phys_disk_num;
5746
5747 if (mpt_config(ioc, &cfg) != 0) {
5748 rc = -EFAULT;
5749 goto out;
5750 }
5751
5752 rc = 0;
5753 memcpy(phys_disk, buffer, sizeof(*buffer));
5754 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5755
5756 out:
5757
5758 if (buffer)
5759 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5760 dma_handle);
5761
5762 return rc;
5763}
5764
Linus Torvalds1da177e2005-04-16 15:20:36 -07005765/**
Kashyap, Desaia7938b02009-05-29 16:53:56 +05305766 * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
5767 * @ioc: Pointer to a Adapter Structure
5768 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5769 *
5770 * Return:
5771 * returns number paths
5772 **/
5773int
5774mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
5775{
5776 CONFIGPARMS cfg;
5777 ConfigPageHeader_t hdr;
5778 dma_addr_t dma_handle;
5779 pRaidPhysDiskPage1_t buffer = NULL;
5780 int rc;
5781
5782 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5783 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5784
5785 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5786 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5787 hdr.PageNumber = 1;
5788 cfg.cfghdr.hdr = &hdr;
5789 cfg.physAddr = -1;
5790 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5791
5792 if (mpt_config(ioc, &cfg) != 0) {
5793 rc = 0;
5794 goto out;
5795 }
5796
5797 if (!hdr.PageLength) {
5798 rc = 0;
5799 goto out;
5800 }
5801
5802 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5803 &dma_handle);
5804
5805 if (!buffer) {
5806 rc = 0;
5807 goto out;
5808 }
5809
5810 cfg.physAddr = dma_handle;
5811 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5812 cfg.pageAddr = phys_disk_num;
5813
5814 if (mpt_config(ioc, &cfg) != 0) {
5815 rc = 0;
5816 goto out;
5817 }
5818
5819 rc = buffer->NumPhysDiskPaths;
5820 out:
5821
5822 if (buffer)
5823 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5824 dma_handle);
5825
5826 return rc;
5827}
5828EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
5829
5830/**
5831 * mpt_raid_phys_disk_pg1 - returns phys disk page 1
5832 * @ioc: Pointer to a Adapter Structure
5833 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5834 * @phys_disk: requested payload data returned
5835 *
5836 * Return:
5837 * 0 on success
5838 * -EFAULT if read of config page header fails or data pointer not NULL
5839 * -ENOMEM if pci_alloc failed
5840 **/
5841int
5842mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
5843 RaidPhysDiskPage1_t *phys_disk)
5844{
5845 CONFIGPARMS cfg;
5846 ConfigPageHeader_t hdr;
5847 dma_addr_t dma_handle;
5848 pRaidPhysDiskPage1_t buffer = NULL;
5849 int rc;
5850 int i;
5851 __le64 sas_address;
5852
5853 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5854 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5855 rc = 0;
5856
5857 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5858 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5859 hdr.PageNumber = 1;
5860 cfg.cfghdr.hdr = &hdr;
5861 cfg.physAddr = -1;
5862 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5863
5864 if (mpt_config(ioc, &cfg) != 0) {
5865 rc = -EFAULT;
5866 goto out;
5867 }
5868
5869 if (!hdr.PageLength) {
5870 rc = -EFAULT;
5871 goto out;
5872 }
5873
5874 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5875 &dma_handle);
5876
5877 if (!buffer) {
5878 rc = -ENOMEM;
5879 goto out;
5880 }
5881
5882 cfg.physAddr = dma_handle;
5883 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5884 cfg.pageAddr = phys_disk_num;
5885
5886 if (mpt_config(ioc, &cfg) != 0) {
5887 rc = -EFAULT;
5888 goto out;
5889 }
5890
5891 phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
5892 phys_disk->PhysDiskNum = phys_disk_num;
5893 for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
5894 phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
5895 phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
5896 phys_disk->Path[i].OwnerIdentifier =
5897 buffer->Path[i].OwnerIdentifier;
5898 phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
5899 memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
5900 sas_address = le64_to_cpu(sas_address);
5901 memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
5902 memcpy(&sas_address,
5903 &buffer->Path[i].OwnerWWID, sizeof(__le64));
5904 sas_address = le64_to_cpu(sas_address);
5905 memcpy(&phys_disk->Path[i].OwnerWWID,
5906 &sas_address, sizeof(__le64));
5907 }
5908
5909 out:
5910
5911 if (buffer)
5912 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5913 dma_handle);
5914
5915 return rc;
5916}
5917EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
5918
5919
5920/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005921 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5922 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005923 *
5924 * Return:
5925 * 0 on success
5926 * -EFAULT if read of config page header fails or data pointer not NULL
5927 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005928 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005929int
5930mpt_findImVolumes(MPT_ADAPTER *ioc)
5931{
5932 IOCPage2_t *pIoc2;
5933 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005934 dma_addr_t ioc2_dma;
5935 CONFIGPARMS cfg;
5936 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005937 int rc = 0;
5938 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005939 int i;
5940
5941 if (!ioc->ir_firmware)
5942 return 0;
5943
5944 /* Free the old page
5945 */
5946 kfree(ioc->raid_data.pIocPg2);
5947 ioc->raid_data.pIocPg2 = NULL;
5948 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005949
5950 /* Read IOCP2 header then the page.
5951 */
5952 header.PageVersion = 0;
5953 header.PageLength = 0;
5954 header.PageNumber = 2;
5955 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005956 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957 cfg.physAddr = -1;
5958 cfg.pageAddr = 0;
5959 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5960 cfg.dir = 0;
5961 cfg.timeout = 0;
5962 if (mpt_config(ioc, &cfg) != 0)
5963 return -EFAULT;
5964
5965 if (header.PageLength == 0)
5966 return -EFAULT;
5967
5968 iocpage2sz = header.PageLength * 4;
5969 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5970 if (!pIoc2)
5971 return -ENOMEM;
5972
5973 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5974 cfg.physAddr = ioc2_dma;
5975 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005976 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977
Eric Mooreb506ade2007-01-29 09:45:37 -07005978 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5979 if (!mem)
5980 goto out;
5981
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005983 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005984
Eric Mooreb506ade2007-01-29 09:45:37 -07005985 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986
Eric Mooreb506ade2007-01-29 09:45:37 -07005987 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5988 mpt_inactive_raid_volumes(ioc,
5989 pIoc2->RaidVolume[i].VolumeBus,
5990 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005991
Eric Mooreb506ade2007-01-29 09:45:37 -07005992 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005993 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5994
5995 return rc;
5996}
5997
Moore, Ericc972c702006-03-14 09:14:06 -07005998static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005999mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
6000{
6001 IOCPage3_t *pIoc3;
6002 u8 *mem;
6003 CONFIGPARMS cfg;
6004 ConfigPageHeader_t header;
6005 dma_addr_t ioc3_dma;
6006 int iocpage3sz = 0;
6007
6008 /* Free the old page
6009 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006010 kfree(ioc->raid_data.pIocPg3);
6011 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006012
6013 /* There is at least one physical disk.
6014 * Read and save IOC Page 3
6015 */
6016 header.PageVersion = 0;
6017 header.PageLength = 0;
6018 header.PageNumber = 3;
6019 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006020 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006021 cfg.physAddr = -1;
6022 cfg.pageAddr = 0;
6023 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6024 cfg.dir = 0;
6025 cfg.timeout = 0;
6026 if (mpt_config(ioc, &cfg) != 0)
6027 return 0;
6028
6029 if (header.PageLength == 0)
6030 return 0;
6031
6032 /* Read Header good, alloc memory
6033 */
6034 iocpage3sz = header.PageLength * 4;
6035 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
6036 if (!pIoc3)
6037 return 0;
6038
6039 /* Read the Page and save the data
6040 * into malloc'd memory.
6041 */
6042 cfg.physAddr = ioc3_dma;
6043 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6044 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07006045 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006046 if (mem) {
6047 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006048 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006049 }
6050 }
6051
6052 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
6053
6054 return 0;
6055}
6056
6057static void
6058mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
6059{
6060 IOCPage4_t *pIoc4;
6061 CONFIGPARMS cfg;
6062 ConfigPageHeader_t header;
6063 dma_addr_t ioc4_dma;
6064 int iocpage4sz;
6065
6066 /* Read and save IOC Page 4
6067 */
6068 header.PageVersion = 0;
6069 header.PageLength = 0;
6070 header.PageNumber = 4;
6071 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006072 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006073 cfg.physAddr = -1;
6074 cfg.pageAddr = 0;
6075 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6076 cfg.dir = 0;
6077 cfg.timeout = 0;
6078 if (mpt_config(ioc, &cfg) != 0)
6079 return;
6080
6081 if (header.PageLength == 0)
6082 return;
6083
6084 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
6085 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
6086 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
6087 if (!pIoc4)
6088 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06006089 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006090 } else {
6091 ioc4_dma = ioc->spi_data.IocPg4_dma;
6092 iocpage4sz = ioc->spi_data.IocPg4Sz;
6093 }
6094
6095 /* Read the Page into dma memory.
6096 */
6097 cfg.physAddr = ioc4_dma;
6098 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6099 if (mpt_config(ioc, &cfg) == 0) {
6100 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
6101 ioc->spi_data.IocPg4_dma = ioc4_dma;
6102 ioc->spi_data.IocPg4Sz = iocpage4sz;
6103 } else {
6104 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
6105 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06006106 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006107 }
6108}
6109
6110static void
6111mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
6112{
6113 IOCPage1_t *pIoc1;
6114 CONFIGPARMS cfg;
6115 ConfigPageHeader_t header;
6116 dma_addr_t ioc1_dma;
6117 int iocpage1sz = 0;
6118 u32 tmp;
6119
6120 /* Check the Coalescing Timeout in IOC Page 1
6121 */
6122 header.PageVersion = 0;
6123 header.PageLength = 0;
6124 header.PageNumber = 1;
6125 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006126 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006127 cfg.physAddr = -1;
6128 cfg.pageAddr = 0;
6129 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6130 cfg.dir = 0;
6131 cfg.timeout = 0;
6132 if (mpt_config(ioc, &cfg) != 0)
6133 return;
6134
6135 if (header.PageLength == 0)
6136 return;
6137
6138 /* Read Header good, alloc memory
6139 */
6140 iocpage1sz = header.PageLength * 4;
6141 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
6142 if (!pIoc1)
6143 return;
6144
6145 /* Read the Page and check coalescing timeout
6146 */
6147 cfg.physAddr = ioc1_dma;
6148 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6149 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306150
Linus Torvalds1da177e2005-04-16 15:20:36 -07006151 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
6152 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
6153 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
6154
Prakash, Sathya436ace72007-07-24 15:42:08 +05306155 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006156 ioc->name, tmp));
6157
6158 if (tmp > MPT_COALESCING_TIMEOUT) {
6159 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
6160
6161 /* Write NVRAM and current
6162 */
6163 cfg.dir = 1;
6164 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
6165 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306166 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006167 ioc->name, MPT_COALESCING_TIMEOUT));
6168
6169 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
6170 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306171 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6172 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006173 ioc->name, MPT_COALESCING_TIMEOUT));
6174 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306175 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6176 "Reset NVRAM Coalescing Timeout Failed\n",
6177 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006178 }
6179
6180 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306181 dprintk(ioc, printk(MYIOC_s_WARN_FMT
6182 "Reset of Current Coalescing Timeout Failed!\n",
6183 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006184 }
6185 }
6186
6187 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306188 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006189 }
6190 }
6191
6192 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
6193
6194 return;
6195}
6196
Prakash, Sathyaedb90682007-07-17 14:39:14 +05306197static void
6198mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
6199{
6200 CONFIGPARMS cfg;
6201 ConfigPageHeader_t hdr;
6202 dma_addr_t buf_dma;
6203 ManufacturingPage0_t *pbuf = NULL;
6204
6205 memset(&cfg, 0 , sizeof(CONFIGPARMS));
6206 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
6207
6208 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
6209 cfg.cfghdr.hdr = &hdr;
6210 cfg.physAddr = -1;
6211 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6212 cfg.timeout = 10;
6213
6214 if (mpt_config(ioc, &cfg) != 0)
6215 goto out;
6216
6217 if (!cfg.cfghdr.hdr->PageLength)
6218 goto out;
6219
6220 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6221 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
6222 if (!pbuf)
6223 goto out;
6224
6225 cfg.physAddr = buf_dma;
6226
6227 if (mpt_config(ioc, &cfg) != 0)
6228 goto out;
6229
6230 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
6231 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
6232 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
6233
6234 out:
6235
6236 if (pbuf)
6237 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
6238}
6239
Linus Torvalds1da177e2005-04-16 15:20:36 -07006240/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006241/**
6242 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006243 * @ioc: Pointer to MPT_ADAPTER structure
6244 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05306245 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07006246 */
6247static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05306248SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006249{
Kashyap, Desaifd761752009-05-29 16:39:06 +05306250 EventNotification_t evn;
6251 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006252
Kashyap, Desaifd761752009-05-29 16:39:06 +05306253 memset(&evn, 0, sizeof(EventNotification_t));
6254 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006255
Kashyap, Desaifd761752009-05-29 16:39:06 +05306256 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
6257 evn.Switch = EvSwitch;
6258 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006259
Kashyap, Desaifd761752009-05-29 16:39:06 +05306260 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6261 "Sending EventNotification (%d) request %p\n",
6262 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006263
Kashyap, Desaifd761752009-05-29 16:39:06 +05306264 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6265 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6266 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006267}
6268
6269/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6270/**
6271 * SendEventAck - Send EventAck request to MPT adapter.
6272 * @ioc: Pointer to MPT_ADAPTER structure
6273 * @evnp: Pointer to original EventNotification request
6274 */
6275static int
6276SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6277{
6278 EventAck_t *pAck;
6279
6280 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306281 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306282 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006283 return -1;
6284 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006285
Prakash, Sathya436ace72007-07-24 15:42:08 +05306286 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006287
6288 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6289 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006290 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006291 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006292 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006293 pAck->Event = evnp->Event;
6294 pAck->EventContext = evnp->EventContext;
6295
6296 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6297
6298 return 0;
6299}
6300
6301/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6302/**
6303 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006304 * @ioc: Pointer to an adapter structure
6305 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006306 * action, page address, direction, physical address
6307 * and pointer to a configuration page header
6308 * Page header is updated.
6309 *
6310 * Returns 0 for success
6311 * -EPERM if not allowed due to ISR context
6312 * -EAGAIN if no msg frames currently available
6313 * -EFAULT for non-successful reply or no reply (timeout)
6314 */
6315int
6316mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6317{
6318 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306319 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006320 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006321 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306322 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006323 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306324 long timeout;
6325 int ret;
6326 u8 page_type = 0, extend_page;
6327 unsigned long timeleft;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306328 unsigned long flags;
6329 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306330 u8 issue_hard_reset = 0;
6331 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006332
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006333 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006334 * to be in ISR context, because that is fatal!
6335 */
6336 in_isr = in_interrupt();
6337 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306338 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006339 ioc->name));
6340 return -EPERM;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306341 }
6342
6343 /* don't send a config page during diag reset */
6344 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6345 if (ioc->ioc_reset_in_progress) {
6346 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6347 "%s: busy with host reset\n", ioc->name, __func__));
6348 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6349 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006350 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306351 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006352
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306353 /* don't send if no chance of success */
6354 if (!ioc->active ||
6355 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6356 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6357 "%s: ioc not operational, %d, %xh\n",
6358 ioc->name, __func__, ioc->active,
6359 mpt_GetIocState(ioc, 0)));
6360 return -EFAULT;
6361 }
6362
6363 retry_config:
6364 mutex_lock(&ioc->mptbase_cmds.mutex);
6365 /* init the internal cmd struct */
6366 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6367 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6368
Linus Torvalds1da177e2005-04-16 15:20:36 -07006369 /* Get and Populate a free Frame
6370 */
6371 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306372 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6373 "mpt_config: no msg frames!\n", ioc->name));
6374 ret = -EAGAIN;
6375 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006376 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306377
Linus Torvalds1da177e2005-04-16 15:20:36 -07006378 pReq = (Config_t *)mf;
6379 pReq->Action = pCfg->action;
6380 pReq->Reserved = 0;
6381 pReq->ChainOffset = 0;
6382 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006383
6384 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006385 pReq->ExtPageLength = 0;
6386 pReq->ExtPageType = 0;
6387 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006388
Linus Torvalds1da177e2005-04-16 15:20:36 -07006389 for (ii=0; ii < 8; ii++)
6390 pReq->Reserved2[ii] = 0;
6391
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006392 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6393 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6394 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6395 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6396
6397 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6398 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6399 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6400 pReq->ExtPageType = pExtHdr->ExtPageType;
6401 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6402
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306403 /* Page Length must be treated as a reserved field for the
6404 * extended header.
6405 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006406 pReq->Header.PageLength = 0;
6407 }
6408
Linus Torvalds1da177e2005-04-16 15:20:36 -07006409 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6410
6411 /* Add a SGE to the config request.
6412 */
6413 if (pCfg->dir)
6414 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6415 else
6416 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6417
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306418 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6419 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006420 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306421 page_type = pReq->ExtPageType;
6422 extend_page = 1;
6423 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006424 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306425 page_type = pReq->Header.PageType;
6426 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006427 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006428
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306429 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6430 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6431 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6432
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306433 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306434 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006435 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306436 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6437 timeout);
6438 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6439 ret = -ETIME;
6440 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6441 "Failed Sending Config request type 0x%x, page 0x%x,"
6442 " action %d, status %xh, time left %ld\n\n",
6443 ioc->name, page_type, pReq->Header.PageNumber,
6444 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6445 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6446 goto out;
6447 if (!timeleft)
6448 issue_hard_reset = 1;
6449 goto out;
6450 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006451
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306452 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6453 ret = -1;
6454 goto out;
6455 }
6456 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6457 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6458 if (ret == MPI_IOCSTATUS_SUCCESS) {
6459 if (extend_page) {
6460 pCfg->cfghdr.ehdr->ExtPageLength =
6461 le16_to_cpu(pReply->ExtPageLength);
6462 pCfg->cfghdr.ehdr->ExtPageType =
6463 pReply->ExtPageType;
6464 }
6465 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6466 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6467 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6468 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006469
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306470 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006471
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306472 if (retry_count)
6473 printk(MYIOC_s_INFO_FMT "Retry completed "
6474 "ret=0x%x timeleft=%ld\n",
6475 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006476
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306477 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6478 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006479
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306480out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006481
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306482 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6483 mutex_unlock(&ioc->mptbase_cmds.mutex);
6484 if (issue_hard_reset) {
6485 issue_hard_reset = 0;
6486 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
6487 ioc->name, __func__);
6488 mpt_HardResetHandler(ioc, CAN_SLEEP);
6489 mpt_free_msg_frame(ioc, mf);
6490 /* attempt one retry for a timed out command */
6491 if (!retry_count) {
6492 printk(MYIOC_s_INFO_FMT
6493 "Attempting Retry Config request"
6494 " type 0x%x, page 0x%x,"
6495 " action %d\n", ioc->name, page_type,
6496 pCfg->cfghdr.hdr->PageNumber, pCfg->action);
6497 retry_count++;
6498 goto retry_config;
6499 }
6500 }
6501 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006502
Linus Torvalds1da177e2005-04-16 15:20:36 -07006503}
6504
6505/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006506/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006507 * mpt_ioc_reset - Base cleanup for hard reset
6508 * @ioc: Pointer to the adapter structure
6509 * @reset_phase: Indicates pre- or post-reset functionality
6510 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006511 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006512 */
6513static int
6514mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6515{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306516 switch (reset_phase) {
6517 case MPT_IOC_SETUP_RESET:
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306518 ioc->taskmgmt_quiesce_io = 1;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306519 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6520 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
6521 break;
6522 case MPT_IOC_PRE_RESET:
6523 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6524 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
6525 break;
6526 case MPT_IOC_POST_RESET:
6527 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6528 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
6529/* wake up mptbase_cmds */
6530 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6531 ioc->mptbase_cmds.status |=
6532 MPT_MGMT_STATUS_DID_IOCRESET;
6533 complete(&ioc->mptbase_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006534 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306535/* wake up taskmgmt_cmds */
6536 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
6537 ioc->taskmgmt_cmds.status |=
6538 MPT_MGMT_STATUS_DID_IOCRESET;
6539 complete(&ioc->taskmgmt_cmds.done);
6540 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306541 break;
6542 default:
6543 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006544 }
6545
6546 return 1; /* currently means nothing really */
6547}
6548
6549
6550#ifdef CONFIG_PROC_FS /* { */
6551/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6552/*
6553 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6554 */
6555/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006556/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006557 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6558 *
6559 * Returns 0 for success, non-zero for failure.
6560 */
6561static int
6562procmpt_create(void)
6563{
6564 struct proc_dir_entry *ent;
6565
6566 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6567 if (mpt_proc_root_dir == NULL)
6568 return -ENOTDIR;
6569
6570 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6571 if (ent)
6572 ent->read_proc = procmpt_summary_read;
6573
6574 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6575 if (ent)
6576 ent->read_proc = procmpt_version_read;
6577
6578 return 0;
6579}
6580
6581/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006582/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006583 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6584 *
6585 * Returns 0 for success, non-zero for failure.
6586 */
6587static void
6588procmpt_destroy(void)
6589{
6590 remove_proc_entry("version", mpt_proc_root_dir);
6591 remove_proc_entry("summary", mpt_proc_root_dir);
6592 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6593}
6594
6595/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006596/**
6597 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006598 * @buf: Pointer to area to write information
6599 * @start: Pointer to start pointer
6600 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006601 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006602 * @eof: Pointer to EOF integer
6603 * @data: Pointer
6604 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006605 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006606 * Returns number of characters written to process performing the read.
6607 */
6608static int
6609procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6610{
6611 MPT_ADAPTER *ioc;
6612 char *out = buf;
6613 int len;
6614
6615 if (data) {
6616 int more = 0;
6617
6618 ioc = data;
6619 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6620
6621 out += more;
6622 } else {
6623 list_for_each_entry(ioc, &ioc_list, list) {
6624 int more = 0;
6625
6626 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6627
6628 out += more;
6629 if ((out-buf) >= request)
6630 break;
6631 }
6632 }
6633
6634 len = out - buf;
6635
6636 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6637}
6638
6639/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006640/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006641 * procmpt_version_read - Handle read request from /proc/mpt/version.
6642 * @buf: Pointer to area to write information
6643 * @start: Pointer to start pointer
6644 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006645 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006646 * @eof: Pointer to EOF integer
6647 * @data: Pointer
6648 *
6649 * Returns number of characters written to process performing the read.
6650 */
6651static int
6652procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6653{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306654 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006655 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006656 char *drvname;
6657 int len;
6658
6659 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6660 len += sprintf(buf+len, " Fusion MPT base driver\n");
6661
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006662 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006663 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006664 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306665 if (MptCallbacks[cb_idx]) {
6666 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006667 case MPTSPI_DRIVER:
6668 if (!scsi++) drvname = "SPI host";
6669 break;
6670 case MPTFC_DRIVER:
6671 if (!fc++) drvname = "FC host";
6672 break;
6673 case MPTSAS_DRIVER:
6674 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006675 break;
6676 case MPTLAN_DRIVER:
6677 if (!lan++) drvname = "LAN";
6678 break;
6679 case MPTSTM_DRIVER:
6680 if (!targ++) drvname = "SCSI target";
6681 break;
6682 case MPTCTL_DRIVER:
6683 if (!ctl++) drvname = "ioctl";
6684 break;
6685 }
6686
6687 if (drvname)
6688 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6689 }
6690 }
6691
6692 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6693}
6694
6695/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006696/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006697 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6698 * @buf: Pointer to area to write information
6699 * @start: Pointer to start pointer
6700 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006701 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006702 * @eof: Pointer to EOF integer
6703 * @data: Pointer
6704 *
6705 * Returns number of characters written to process performing the read.
6706 */
6707static int
6708procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6709{
6710 MPT_ADAPTER *ioc = data;
6711 int len;
6712 char expVer[32];
6713 int sz;
6714 int p;
6715
6716 mpt_get_fw_exp_ver(expVer, ioc);
6717
6718 len = sprintf(buf, "%s:", ioc->name);
6719 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6720 len += sprintf(buf+len, " (f/w download boot flag set)");
6721// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6722// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6723
6724 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6725 ioc->facts.ProductID,
6726 ioc->prod_name);
6727 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6728 if (ioc->facts.FWImageSize)
6729 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6730 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6731 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6732 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6733
6734 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6735 ioc->facts.CurrentHostMfaHighAddr);
6736 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6737 ioc->facts.CurrentSenseBufferHighAddr);
6738
6739 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6740 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6741
6742 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6743 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6744 /*
6745 * Rounding UP to nearest 4-kB boundary here...
6746 */
6747 sz = (ioc->req_sz * ioc->req_depth) + 128;
6748 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6749 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6750 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6751 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6752 4*ioc->facts.RequestFrameSize,
6753 ioc->facts.GlobalCredits);
6754
6755 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6756 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6757 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6758 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6759 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6760 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6761 ioc->facts.CurReplyFrameSize,
6762 ioc->facts.ReplyQueueDepth);
6763
6764 len += sprintf(buf+len, " MaxDevices = %d\n",
6765 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6766 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6767
6768 /* per-port info */
6769 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6770 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6771 p+1,
6772 ioc->facts.NumberOfPorts);
6773 if (ioc->bus_type == FC) {
6774 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6775 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6776 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6777 a[5], a[4], a[3], a[2], a[1], a[0]);
6778 }
6779 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6780 ioc->fc_port_page0[p].WWNN.High,
6781 ioc->fc_port_page0[p].WWNN.Low,
6782 ioc->fc_port_page0[p].WWPN.High,
6783 ioc->fc_port_page0[p].WWPN.Low);
6784 }
6785 }
6786
6787 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6788}
6789
6790#endif /* CONFIG_PROC_FS } */
6791
6792/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6793static void
6794mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6795{
6796 buf[0] ='\0';
6797 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6798 sprintf(buf, " (Exp %02d%02d)",
6799 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6800 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6801
6802 /* insider hack! */
6803 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6804 strcat(buf, " [MDBG]");
6805 }
6806}
6807
6808/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6809/**
6810 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6811 * @ioc: Pointer to MPT_ADAPTER structure
6812 * @buffer: Pointer to buffer where IOC summary info should be written
6813 * @size: Pointer to number of bytes we wrote (set by this routine)
6814 * @len: Offset at which to start writing in buffer
6815 * @showlan: Display LAN stuff?
6816 *
6817 * This routine writes (english readable) ASCII text, which represents
6818 * a summary of IOC information, to a buffer.
6819 */
6820void
6821mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6822{
6823 char expVer[32];
6824 int y;
6825
6826 mpt_get_fw_exp_ver(expVer, ioc);
6827
6828 /*
6829 * Shorter summary of attached ioc's...
6830 */
6831 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6832 ioc->name,
6833 ioc->prod_name,
6834 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6835 ioc->facts.FWVersion.Word,
6836 expVer,
6837 ioc->facts.NumberOfPorts,
6838 ioc->req_depth);
6839
6840 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6841 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6842 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6843 a[5], a[4], a[3], a[2], a[1], a[0]);
6844 }
6845
Linus Torvalds1da177e2005-04-16 15:20:36 -07006846 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006847
6848 if (!ioc->active)
6849 y += sprintf(buffer+len+y, " (disabled)");
6850
6851 y += sprintf(buffer+len+y, "\n");
6852
6853 *size = y;
6854}
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306855/**
6856 * mpt_set_taskmgmt_in_progress_flag - set flags associated with task managment
6857 * @ioc: Pointer to MPT_ADAPTER structure
6858 *
6859 * Returns 0 for SUCCESS or -1 if FAILED.
6860 *
6861 * If -1 is return, then it was not possible to set the flags
6862 **/
6863int
6864mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6865{
6866 unsigned long flags;
6867 int retval;
6868
6869 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6870 if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
6871 (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
6872 retval = -1;
6873 goto out;
6874 }
6875 retval = 0;
6876 ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306877 ioc->taskmgmt_quiesce_io = 1;
6878 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306879 ioc->alt_ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306880 ioc->alt_ioc->taskmgmt_quiesce_io = 1;
6881 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306882 out:
6883 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6884 return retval;
6885}
6886EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
6887
6888/**
6889 * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task managment
6890 * @ioc: Pointer to MPT_ADAPTER structure
6891 *
6892 **/
6893void
6894mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6895{
6896 unsigned long flags;
6897
6898 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6899 ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306900 ioc->taskmgmt_quiesce_io = 0;
6901 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306902 ioc->alt_ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306903 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
6904 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306905 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6906}
6907EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006908
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306909
6910/**
6911 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6912 * the kernel
6913 * @ioc: Pointer to MPT_ADAPTER structure
6914 *
6915 **/
6916void
6917mpt_halt_firmware(MPT_ADAPTER *ioc)
6918{
6919 u32 ioc_raw_state;
6920
6921 ioc_raw_state = mpt_GetIocState(ioc, 0);
6922
6923 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6924 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6925 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6926 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6927 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6928 } else {
6929 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6930 panic("%s: Firmware is halted due to command timeout\n",
6931 ioc->name);
6932 }
6933}
6934EXPORT_SYMBOL(mpt_halt_firmware);
6935
Linus Torvalds1da177e2005-04-16 15:20:36 -07006936/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6937/*
6938 * Reset Handling
6939 */
6940/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6941/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006942 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006943 * @ioc: Pointer to MPT_ADAPTER structure
6944 * @sleepFlag: Indicates if sleep or schedule must be called.
6945 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006946 * Issues SCSI Task Management call based on input arg values.
6947 * If TaskMgmt fails, returns associated SCSI request.
6948 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006949 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6950 * or a non-interrupt thread. In the former, must not call schedule().
6951 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006952 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006953 * FW reload/initialization failed.
6954 *
6955 * Returns 0 for SUCCESS or -1 if FAILED.
6956 */
6957int
6958mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6959{
6960 int rc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306961 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006962 unsigned long flags;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306963 unsigned long time_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006964
Prakash, Sathya436ace72007-07-24 15:42:08 +05306965 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006966#ifdef MFCNT
6967 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6968 printk("MF count 0x%x !\n", ioc->mfcnt);
6969#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306970 if (mpt_fwfault_debug)
6971 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006972
6973 /* Reset the adapter. Prevent more than 1 call to
6974 * mpt_do_ioc_recovery at any instant in time.
6975 */
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306976 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6977 if (ioc->ioc_reset_in_progress) {
6978 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006979 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006980 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306981 ioc->ioc_reset_in_progress = 1;
6982 if (ioc->alt_ioc)
6983 ioc->alt_ioc->ioc_reset_in_progress = 1;
6984 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006985
6986 /* FIXME: If do_ioc_recovery fails, repeat....
6987 */
6988
6989 /* The SCSI driver needs to adjust timeouts on all current
6990 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006991 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006992 * For all other protocol drivers, this is a no-op.
6993 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05306994 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6995 if (MptResetHandlers[cb_idx]) {
6996 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
6997 if (ioc->alt_ioc)
6998 mpt_signal_reset(cb_idx, ioc->alt_ioc,
6999 MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007000 }
7001 }
7002
Kashyap, Desai2f187862009-05-29 16:52:37 +05307003 time_count = jiffies;
7004 rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
7005 if (rc != 0) {
7006 printk(KERN_WARNING MYNAM
7007 ": WARNING - (%d) Cannot recover %s\n", rc, ioc->name);
7008 } else {
7009 if (ioc->hard_resets < -1)
7010 ioc->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007011 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007012
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307013 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7014 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307015 ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307016 ioc->taskmgmt_in_progress = 0;
7017 if (ioc->alt_ioc) {
7018 ioc->alt_ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307019 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307020 ioc->alt_ioc->taskmgmt_in_progress = 0;
7021 }
7022 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007023
Kashyap, Desai2f187862009-05-29 16:52:37 +05307024 dtmprintk(ioc,
7025 printk(MYIOC_s_DEBUG_FMT
7026 "HardResetHandler: completed (%d seconds): %s\n", ioc->name,
7027 jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?
7028 "SUCCESS" : "FAILED")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007029
7030 return rc;
7031}
7032
Kashyap, Desai2f187862009-05-29 16:52:37 +05307033#ifdef CONFIG_FUSION_LOGGING
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007034static void
Kashyap, Desai2f187862009-05-29 16:52:37 +05307035mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007036{
Eric Moore509e5e52006-04-26 13:22:37 -06007037 char *ds = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307038 u32 evData0;
7039 int ii;
7040 u8 event;
7041 char *evStr = ioc->evStr;
7042
7043 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7044 evData0 = le32_to_cpu(pEventReply->Data[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007045
7046 switch(event) {
7047 case MPI_EVENT_NONE:
7048 ds = "None";
7049 break;
7050 case MPI_EVENT_LOG_DATA:
7051 ds = "Log Data";
7052 break;
7053 case MPI_EVENT_STATE_CHANGE:
7054 ds = "State Change";
7055 break;
7056 case MPI_EVENT_UNIT_ATTENTION:
7057 ds = "Unit Attention";
7058 break;
7059 case MPI_EVENT_IOC_BUS_RESET:
7060 ds = "IOC Bus Reset";
7061 break;
7062 case MPI_EVENT_EXT_BUS_RESET:
7063 ds = "External Bus Reset";
7064 break;
7065 case MPI_EVENT_RESCAN:
7066 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007067 break;
7068 case MPI_EVENT_LINK_STATUS_CHANGE:
7069 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
7070 ds = "Link Status(FAILURE) Change";
7071 else
7072 ds = "Link Status(ACTIVE) Change";
7073 break;
7074 case MPI_EVENT_LOOP_STATE_CHANGE:
7075 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
7076 ds = "Loop State(LIP) Change";
7077 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Kashyap, Desai2f187862009-05-29 16:52:37 +05307078 ds = "Loop State(LPE) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007079 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05307080 ds = "Loop State(LPB) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007081 break;
7082 case MPI_EVENT_LOGOUT:
7083 ds = "Logout";
7084 break;
7085 case MPI_EVENT_EVENT_CHANGE:
7086 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06007087 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007088 else
Eric Moore4f766dc2006-07-11 17:24:07 -06007089 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007090 break;
7091 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007092 {
7093 u8 ReasonCode = (u8)(evData0 >> 16);
7094 switch (ReasonCode) {
7095 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
7096 ds = "Integrated Raid: Volume Created";
7097 break;
7098 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
7099 ds = "Integrated Raid: Volume Deleted";
7100 break;
7101 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
7102 ds = "Integrated Raid: Volume Settings Changed";
7103 break;
7104 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
7105 ds = "Integrated Raid: Volume Status Changed";
7106 break;
7107 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
7108 ds = "Integrated Raid: Volume Physdisk Changed";
7109 break;
7110 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
7111 ds = "Integrated Raid: Physdisk Created";
7112 break;
7113 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
7114 ds = "Integrated Raid: Physdisk Deleted";
7115 break;
7116 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
7117 ds = "Integrated Raid: Physdisk Settings Changed";
7118 break;
7119 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
7120 ds = "Integrated Raid: Physdisk Status Changed";
7121 break;
7122 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
7123 ds = "Integrated Raid: Domain Validation Needed";
7124 break;
7125 case MPI_EVENT_RAID_RC_SMART_DATA :
7126 ds = "Integrated Raid; Smart Data";
7127 break;
7128 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
7129 ds = "Integrated Raid: Replace Action Started";
7130 break;
7131 default:
7132 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007133 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007134 }
7135 break;
7136 }
7137 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
7138 ds = "SCSI Device Status Change";
7139 break;
7140 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
7141 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007142 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007143 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007144 u8 ReasonCode = (u8)(evData0 >> 16);
7145 switch (ReasonCode) {
7146 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007147 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007148 "SAS Device Status Change: Added: "
7149 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007150 break;
7151 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06007152 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007153 "SAS Device Status Change: Deleted: "
7154 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007155 break;
7156 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06007157 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007158 "SAS Device Status Change: SMART Data: "
7159 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007160 break;
7161 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007162 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007163 "SAS Device Status Change: No Persistancy: "
7164 "id=%d channel=%d", id, channel);
7165 break;
7166 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
7167 snprintf(evStr, EVENT_DESCR_STR_SZ,
7168 "SAS Device Status Change: Unsupported Device "
7169 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007170 break;
7171 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
7172 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007173 "SAS Device Status Change: Internal Device "
7174 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007175 break;
7176 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
7177 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007178 "SAS Device Status Change: Internal Task "
7179 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007180 break;
7181 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
7182 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007183 "SAS Device Status Change: Internal Abort "
7184 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007185 break;
7186 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
7187 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007188 "SAS Device Status Change: Internal Clear "
7189 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007190 break;
7191 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
7192 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007193 "SAS Device Status Change: Internal Query "
7194 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007195 break;
7196 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007197 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007198 "SAS Device Status Change: Unknown: "
7199 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06007200 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007201 }
7202 break;
7203 }
7204 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
7205 ds = "Bus Timer Expired";
7206 break;
7207 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07007208 {
7209 u16 curr_depth = (u16)(evData0 >> 16);
7210 u8 channel = (u8)(evData0 >> 8);
7211 u8 id = (u8)(evData0);
7212
7213 snprintf(evStr, EVENT_DESCR_STR_SZ,
7214 "Queue Full: channel=%d id=%d depth=%d",
7215 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007216 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07007217 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007218 case MPI_EVENT_SAS_SES:
7219 ds = "SAS SES Event";
7220 break;
7221 case MPI_EVENT_PERSISTENT_TABLE_FULL:
7222 ds = "Persistent Table Full";
7223 break;
7224 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07007225 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007226 u8 LinkRates = (u8)(evData0 >> 8);
7227 u8 PhyNumber = (u8)(evData0);
7228 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
7229 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
7230 switch (LinkRates) {
7231 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06007232 snprintf(evStr, EVENT_DESCR_STR_SZ,
7233 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007234 " Rate Unknown",PhyNumber);
7235 break;
7236 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06007237 snprintf(evStr, EVENT_DESCR_STR_SZ,
7238 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007239 " Phy Disabled",PhyNumber);
7240 break;
7241 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06007242 snprintf(evStr, EVENT_DESCR_STR_SZ,
7243 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007244 " Failed Speed Nego",PhyNumber);
7245 break;
7246 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06007247 snprintf(evStr, EVENT_DESCR_STR_SZ,
7248 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007249 " Sata OOB Completed",PhyNumber);
7250 break;
7251 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06007252 snprintf(evStr, EVENT_DESCR_STR_SZ,
7253 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007254 " Rate 1.5 Gbps",PhyNumber);
7255 break;
7256 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06007257 snprintf(evStr, EVENT_DESCR_STR_SZ,
7258 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007259 " Rate 3.0 Gpbs",PhyNumber);
7260 break;
7261 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007262 snprintf(evStr, EVENT_DESCR_STR_SZ,
7263 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007264 break;
7265 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007266 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007267 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007268 case MPI_EVENT_SAS_DISCOVERY_ERROR:
7269 ds = "SAS Discovery Error";
7270 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007271 case MPI_EVENT_IR_RESYNC_UPDATE:
7272 {
7273 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06007274 snprintf(evStr, EVENT_DESCR_STR_SZ,
7275 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07007276 break;
7277 }
7278 case MPI_EVENT_IR2:
7279 {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307280 u8 id = (u8)(evData0);
7281 u8 channel = (u8)(evData0 >> 8);
7282 u8 phys_num = (u8)(evData0 >> 24);
Moore, Eric3a892be2006-03-14 09:14:03 -07007283 u8 ReasonCode = (u8)(evData0 >> 16);
Kashyap, Desai2f187862009-05-29 16:52:37 +05307284
Moore, Eric3a892be2006-03-14 09:14:03 -07007285 switch (ReasonCode) {
7286 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307287 snprintf(evStr, EVENT_DESCR_STR_SZ,
7288 "IR2: LD State Changed: "
7289 "id=%d channel=%d phys_num=%d",
7290 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007291 break;
7292 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307293 snprintf(evStr, EVENT_DESCR_STR_SZ,
7294 "IR2: PD State Changed "
7295 "id=%d channel=%d phys_num=%d",
7296 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007297 break;
7298 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307299 snprintf(evStr, EVENT_DESCR_STR_SZ,
7300 "IR2: Bad Block Table Full: "
7301 "id=%d channel=%d phys_num=%d",
7302 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007303 break;
7304 case MPI_EVENT_IR2_RC_PD_INSERTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307305 snprintf(evStr, EVENT_DESCR_STR_SZ,
7306 "IR2: PD Inserted: "
7307 "id=%d channel=%d phys_num=%d",
7308 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007309 break;
7310 case MPI_EVENT_IR2_RC_PD_REMOVED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307311 snprintf(evStr, EVENT_DESCR_STR_SZ,
7312 "IR2: PD Removed: "
7313 "id=%d channel=%d phys_num=%d",
7314 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007315 break;
7316 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307317 snprintf(evStr, EVENT_DESCR_STR_SZ,
7318 "IR2: Foreign CFG Detected: "
7319 "id=%d channel=%d phys_num=%d",
7320 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007321 break;
7322 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307323 snprintf(evStr, EVENT_DESCR_STR_SZ,
7324 "IR2: Rebuild Medium Error: "
7325 "id=%d channel=%d phys_num=%d",
7326 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007327 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05307328 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
7329 snprintf(evStr, EVENT_DESCR_STR_SZ,
7330 "IR2: Dual Port Added: "
7331 "id=%d channel=%d phys_num=%d",
7332 id, channel, phys_num);
7333 break;
7334 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
7335 snprintf(evStr, EVENT_DESCR_STR_SZ,
7336 "IR2: Dual Port Removed: "
7337 "id=%d channel=%d phys_num=%d",
7338 id, channel, phys_num);
7339 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007340 default:
7341 ds = "IR2";
7342 break;
7343 }
7344 break;
7345 }
7346 case MPI_EVENT_SAS_DISCOVERY:
7347 {
7348 if (evData0)
7349 ds = "SAS Discovery: Start";
7350 else
7351 ds = "SAS Discovery: Stop";
7352 break;
7353 }
7354 case MPI_EVENT_LOG_ENTRY_ADDED:
7355 ds = "SAS Log Entry Added";
7356 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007357
Eric Moorec6c727a2007-01-29 09:44:54 -07007358 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
7359 {
7360 u8 phy_num = (u8)(evData0);
7361 u8 port_num = (u8)(evData0 >> 8);
7362 u8 port_width = (u8)(evData0 >> 16);
7363 u8 primative = (u8)(evData0 >> 24);
7364 snprintf(evStr, EVENT_DESCR_STR_SZ,
7365 "SAS Broadcase Primative: phy=%d port=%d "
7366 "width=%d primative=0x%02x",
7367 phy_num, port_num, port_width, primative);
7368 break;
7369 }
7370
7371 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7372 {
7373 u8 reason = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007374
Kashyap, Desai2f187862009-05-29 16:52:37 +05307375 switch (reason) {
7376 case MPI_EVENT_SAS_INIT_RC_ADDED:
7377 ds = "SAS Initiator Status Change: Added";
7378 break;
7379 case MPI_EVENT_SAS_INIT_RC_REMOVED:
7380 ds = "SAS Initiator Status Change: Deleted";
7381 break;
7382 default:
7383 ds = "SAS Initiator Status Change";
7384 break;
7385 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007386 break;
7387 }
7388
7389 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7390 {
7391 u8 max_init = (u8)(evData0);
7392 u8 current_init = (u8)(evData0 >> 8);
7393
7394 snprintf(evStr, EVENT_DESCR_STR_SZ,
7395 "SAS Initiator Device Table Overflow: max initiators=%02d "
7396 "current initators=%02d",
7397 max_init, current_init);
7398 break;
7399 }
7400 case MPI_EVENT_SAS_SMP_ERROR:
7401 {
7402 u8 status = (u8)(evData0);
7403 u8 port_num = (u8)(evData0 >> 8);
7404 u8 result = (u8)(evData0 >> 16);
7405
7406 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7407 snprintf(evStr, EVENT_DESCR_STR_SZ,
7408 "SAS SMP Error: port=%d result=0x%02x",
7409 port_num, result);
7410 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7411 snprintf(evStr, EVENT_DESCR_STR_SZ,
7412 "SAS SMP Error: port=%d : CRC Error",
7413 port_num);
7414 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7415 snprintf(evStr, EVENT_DESCR_STR_SZ,
7416 "SAS SMP Error: port=%d : Timeout",
7417 port_num);
7418 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7419 snprintf(evStr, EVENT_DESCR_STR_SZ,
7420 "SAS SMP Error: port=%d : No Destination",
7421 port_num);
7422 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7423 snprintf(evStr, EVENT_DESCR_STR_SZ,
7424 "SAS SMP Error: port=%d : Bad Destination",
7425 port_num);
7426 else
7427 snprintf(evStr, EVENT_DESCR_STR_SZ,
7428 "SAS SMP Error: port=%d : status=0x%02x",
7429 port_num, status);
7430 break;
7431 }
7432
Kashyap, Desai2f187862009-05-29 16:52:37 +05307433 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
7434 {
7435 u8 reason = (u8)(evData0);
7436
7437 switch (reason) {
7438 case MPI_EVENT_SAS_EXP_RC_ADDED:
7439 ds = "Expander Status Change: Added";
7440 break;
7441 case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
7442 ds = "Expander Status Change: Deleted";
7443 break;
7444 default:
7445 ds = "Expander Status Change";
7446 break;
7447 }
7448 break;
7449 }
7450
Linus Torvalds1da177e2005-04-16 15:20:36 -07007451 /*
7452 * MPT base "custom" events may be added here...
7453 */
7454 default:
7455 ds = "Unknown";
7456 break;
7457 }
Eric Moore509e5e52006-04-26 13:22:37 -06007458 if (ds)
7459 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007460
Kashyap, Desai2f187862009-05-29 16:52:37 +05307461
7462 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7463 "MPT event:(%02Xh) : %s\n",
7464 ioc->name, event, evStr));
7465
7466 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
7467 ": Event data:\n"));
7468 for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
7469 devtverboseprintk(ioc, printk(" %08x",
7470 le32_to_cpu(pEventReply->Data[ii])));
7471 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
7472}
7473#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007474/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007475/**
7476 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007477 * @ioc: Pointer to MPT_ADAPTER structure
7478 * @pEventReply: Pointer to EventNotification reply frame
7479 * @evHandlers: Pointer to integer, number of event handlers
7480 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007481 * Routes a received EventNotificationReply to all currently registered
7482 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007483 * Returns sum of event handlers return values.
7484 */
7485static int
7486ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7487{
7488 u16 evDataLen;
7489 u32 evData0 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007490 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307491 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007492 int r = 0;
7493 int handlers = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007494 u8 event;
7495
7496 /*
7497 * Do platform normalization of values
7498 */
7499 event = le32_to_cpu(pEventReply->Event) & 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007500 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7501 if (evDataLen) {
7502 evData0 = le32_to_cpu(pEventReply->Data[0]);
7503 }
7504
Prakash, Sathya436ace72007-07-24 15:42:08 +05307505#ifdef CONFIG_FUSION_LOGGING
Kashyap, Desai2f187862009-05-29 16:52:37 +05307506 if (evDataLen)
7507 mpt_display_event_info(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007508#endif
7509
7510 /*
7511 * Do general / base driver event processing
7512 */
7513 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007514 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7515 if (evDataLen) {
7516 u8 evState = evData0 & 0xFF;
7517
7518 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7519
7520 /* Update EventState field in cached IocFacts */
7521 if (ioc->facts.Function) {
7522 ioc->facts.EventState = evState;
7523 }
7524 }
7525 break;
Moore, Ericece50912006-01-16 18:53:19 -07007526 case MPI_EVENT_INTEGRATED_RAID:
7527 mptbase_raid_process_event_data(ioc,
7528 (MpiEventDataRaid_t *)pEventReply->Data);
7529 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007530 default:
7531 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007532 }
7533
7534 /*
7535 * Should this event be logged? Events are written sequentially.
7536 * When buffer is full, start again at the top.
7537 */
7538 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7539 int idx;
7540
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007541 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007542
7543 ioc->events[idx].event = event;
7544 ioc->events[idx].eventContext = ioc->eventContext;
7545
7546 for (ii = 0; ii < 2; ii++) {
7547 if (ii < evDataLen)
7548 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7549 else
7550 ioc->events[idx].data[ii] = 0;
7551 }
7552
7553 ioc->eventContext++;
7554 }
7555
7556
7557 /*
7558 * Call each currently registered protocol event handler.
7559 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007560 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307561 if (MptEvHandlers[cb_idx]) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307562 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7563 "Routing Event to event handler #%d\n",
7564 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307565 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007566 handlers++;
7567 }
7568 }
7569 /* FIXME? Examine results here? */
7570
7571 /*
7572 * If needed, send (a single) EventAck.
7573 */
7574 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307575 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007576 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007577 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307578 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007579 ioc->name, ii));
7580 }
7581 }
7582
7583 *evHandlers = handlers;
7584 return r;
7585}
7586
7587/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007588/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007589 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7590 * @ioc: Pointer to MPT_ADAPTER structure
7591 * @log_info: U32 LogInfo reply word from the IOC
7592 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007593 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007594 */
7595static void
7596mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7597{
Eric Moore7c431e52007-06-13 16:34:36 -06007598 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007599
Eric Moore7c431e52007-06-13 16:34:36 -06007600 switch (log_info & 0xFF000000) {
7601 case MPI_IOCLOGINFO_FC_INIT_BASE:
7602 desc = "FCP Initiator";
7603 break;
7604 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7605 desc = "FCP Target";
7606 break;
7607 case MPI_IOCLOGINFO_FC_LAN_BASE:
7608 desc = "LAN";
7609 break;
7610 case MPI_IOCLOGINFO_FC_MSG_BASE:
7611 desc = "MPI Message Layer";
7612 break;
7613 case MPI_IOCLOGINFO_FC_LINK_BASE:
7614 desc = "FC Link";
7615 break;
7616 case MPI_IOCLOGINFO_FC_CTX_BASE:
7617 desc = "Context Manager";
7618 break;
7619 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7620 desc = "Invalid Field Offset";
7621 break;
7622 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7623 desc = "State Change Info";
7624 break;
7625 }
7626
7627 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7628 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007629}
7630
7631/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007632/**
Moore, Eric335a9412006-01-17 17:06:23 -07007633 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007634 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007635 * @log_info: U32 LogInfo word from the IOC
7636 *
7637 * Refer to lsi/sp_log.h.
7638 */
7639static void
Moore, Eric335a9412006-01-17 17:06:23 -07007640mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007641{
7642 u32 info = log_info & 0x00FF0000;
7643 char *desc = "unknown";
7644
7645 switch (info) {
7646 case 0x00010000:
7647 desc = "bug! MID not found";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007648 break;
7649
7650 case 0x00020000:
7651 desc = "Parity Error";
7652 break;
7653
7654 case 0x00030000:
7655 desc = "ASYNC Outbound Overrun";
7656 break;
7657
7658 case 0x00040000:
7659 desc = "SYNC Offset Error";
7660 break;
7661
7662 case 0x00050000:
7663 desc = "BM Change";
7664 break;
7665
7666 case 0x00060000:
7667 desc = "Msg In Overflow";
7668 break;
7669
7670 case 0x00070000:
7671 desc = "DMA Error";
7672 break;
7673
7674 case 0x00080000:
7675 desc = "Outbound DMA Overrun";
7676 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007677
Linus Torvalds1da177e2005-04-16 15:20:36 -07007678 case 0x00090000:
7679 desc = "Task Management";
7680 break;
7681
7682 case 0x000A0000:
7683 desc = "Device Problem";
7684 break;
7685
7686 case 0x000B0000:
7687 desc = "Invalid Phase Change";
7688 break;
7689
7690 case 0x000C0000:
7691 desc = "Untagged Table Size";
7692 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007693
Linus Torvalds1da177e2005-04-16 15:20:36 -07007694 }
7695
7696 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7697}
7698
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007699/* strings for sas loginfo */
7700 static char *originator_str[] = {
7701 "IOP", /* 00h */
7702 "PL", /* 01h */
7703 "IR" /* 02h */
7704 };
7705 static char *iop_code_str[] = {
7706 NULL, /* 00h */
7707 "Invalid SAS Address", /* 01h */
7708 NULL, /* 02h */
7709 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007710 "Diag Message Error", /* 04h */
7711 "Task Terminated", /* 05h */
7712 "Enclosure Management", /* 06h */
7713 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007714 };
7715 static char *pl_code_str[] = {
7716 NULL, /* 00h */
7717 "Open Failure", /* 01h */
7718 "Invalid Scatter Gather List", /* 02h */
7719 "Wrong Relative Offset or Frame Length", /* 03h */
7720 "Frame Transfer Error", /* 04h */
7721 "Transmit Frame Connected Low", /* 05h */
7722 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7723 "SATA Read Log Receive Data Error", /* 07h */
7724 "SATA NCQ Fail All Commands After Error", /* 08h */
7725 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7726 "Receive Frame Invalid Message", /* 0Ah */
7727 "Receive Context Message Valid Error", /* 0Bh */
7728 "Receive Frame Current Frame Error", /* 0Ch */
7729 "SATA Link Down", /* 0Dh */
7730 "Discovery SATA Init W IOS", /* 0Eh */
7731 "Config Invalid Page", /* 0Fh */
7732 "Discovery SATA Init Timeout", /* 10h */
7733 "Reset", /* 11h */
7734 "Abort", /* 12h */
7735 "IO Not Yet Executed", /* 13h */
7736 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007737 "Persistent Reservation Out Not Affiliation "
7738 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007739 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007740 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007741 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007742 NULL, /* 19h */
7743 NULL, /* 1Ah */
7744 NULL, /* 1Bh */
7745 NULL, /* 1Ch */
7746 NULL, /* 1Dh */
7747 NULL, /* 1Eh */
7748 NULL, /* 1Fh */
7749 "Enclosure Management" /* 20h */
7750 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007751 static char *ir_code_str[] = {
7752 "Raid Action Error", /* 00h */
7753 NULL, /* 00h */
7754 NULL, /* 01h */
7755 NULL, /* 02h */
7756 NULL, /* 03h */
7757 NULL, /* 04h */
7758 NULL, /* 05h */
7759 NULL, /* 06h */
7760 NULL /* 07h */
7761 };
7762 static char *raid_sub_code_str[] = {
7763 NULL, /* 00h */
7764 "Volume Creation Failed: Data Passed too "
7765 "Large", /* 01h */
7766 "Volume Creation Failed: Duplicate Volumes "
7767 "Attempted", /* 02h */
7768 "Volume Creation Failed: Max Number "
7769 "Supported Volumes Exceeded", /* 03h */
7770 "Volume Creation Failed: DMA Error", /* 04h */
7771 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7772 "Volume Creation Failed: Error Reading "
7773 "MFG Page 4", /* 06h */
7774 "Volume Creation Failed: Creating Internal "
7775 "Structures", /* 07h */
7776 NULL, /* 08h */
7777 NULL, /* 09h */
7778 NULL, /* 0Ah */
7779 NULL, /* 0Bh */
7780 NULL, /* 0Ch */
7781 NULL, /* 0Dh */
7782 NULL, /* 0Eh */
7783 NULL, /* 0Fh */
7784 "Activation failed: Already Active Volume", /* 10h */
7785 "Activation failed: Unsupported Volume Type", /* 11h */
7786 "Activation failed: Too Many Active Volumes", /* 12h */
7787 "Activation failed: Volume ID in Use", /* 13h */
7788 "Activation failed: Reported Failure", /* 14h */
7789 "Activation failed: Importing a Volume", /* 15h */
7790 NULL, /* 16h */
7791 NULL, /* 17h */
7792 NULL, /* 18h */
7793 NULL, /* 19h */
7794 NULL, /* 1Ah */
7795 NULL, /* 1Bh */
7796 NULL, /* 1Ch */
7797 NULL, /* 1Dh */
7798 NULL, /* 1Eh */
7799 NULL, /* 1Fh */
7800 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7801 "Phys Disk failed: Data Passed too Large", /* 21h */
7802 "Phys Disk failed: DMA Error", /* 22h */
7803 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7804 "Phys Disk failed: Creating Phys Disk Config "
7805 "Page", /* 24h */
7806 NULL, /* 25h */
7807 NULL, /* 26h */
7808 NULL, /* 27h */
7809 NULL, /* 28h */
7810 NULL, /* 29h */
7811 NULL, /* 2Ah */
7812 NULL, /* 2Bh */
7813 NULL, /* 2Ch */
7814 NULL, /* 2Dh */
7815 NULL, /* 2Eh */
7816 NULL, /* 2Fh */
7817 "Compatibility Error: IR Disabled", /* 30h */
7818 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7819 "Compatibility Error: Device not Direct Access "
7820 "Device ", /* 32h */
7821 "Compatibility Error: Removable Device Found", /* 33h */
7822 "Compatibility Error: Device SCSI Version not "
7823 "2 or Higher", /* 34h */
7824 "Compatibility Error: SATA Device, 48 BIT LBA "
7825 "not Supported", /* 35h */
7826 "Compatibility Error: Device doesn't have "
7827 "512 Byte Block Sizes", /* 36h */
7828 "Compatibility Error: Volume Type Check Failed", /* 37h */
7829 "Compatibility Error: Volume Type is "
7830 "Unsupported by FW", /* 38h */
7831 "Compatibility Error: Disk Drive too Small for "
7832 "use in Volume", /* 39h */
7833 "Compatibility Error: Phys Disk for Create "
7834 "Volume not Found", /* 3Ah */
7835 "Compatibility Error: Too Many or too Few "
7836 "Disks for Volume Type", /* 3Bh */
7837 "Compatibility Error: Disk stripe Sizes "
7838 "Must be 64KB", /* 3Ch */
7839 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7840 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007841
7842/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007843/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007844 * mpt_sas_log_info - Log information returned from SAS IOC.
7845 * @ioc: Pointer to MPT_ADAPTER structure
7846 * @log_info: U32 LogInfo reply word from the IOC
7847 *
7848 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007849 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007850static void
7851mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7852{
7853union loginfo_type {
7854 u32 loginfo;
7855 struct {
7856 u32 subcode:16;
7857 u32 code:8;
7858 u32 originator:4;
7859 u32 bus_type:4;
7860 }dw;
7861};
7862 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007863 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007864 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007865 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007866
7867 sas_loginfo.loginfo = log_info;
7868 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007869 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007870 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007871
7872 originator_desc = originator_str[sas_loginfo.dw.originator];
7873
7874 switch (sas_loginfo.dw.originator) {
7875
7876 case 0: /* IOP */
7877 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007878 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007879 code_desc = iop_code_str[sas_loginfo.dw.code];
7880 break;
7881 case 1: /* PL */
7882 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007883 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007884 code_desc = pl_code_str[sas_loginfo.dw.code];
7885 break;
7886 case 2: /* IR */
7887 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007888 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007889 break;
7890 code_desc = ir_code_str[sas_loginfo.dw.code];
7891 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007892 ARRAY_SIZE(raid_sub_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007893 break;
7894 if (sas_loginfo.dw.code == 0)
7895 sub_code_desc =
7896 raid_sub_code_str[sas_loginfo.dw.subcode];
7897 break;
7898 default:
7899 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007900 }
7901
Eric Moorec6c727a2007-01-29 09:44:54 -07007902 if (sub_code_desc != NULL)
7903 printk(MYIOC_s_INFO_FMT
7904 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7905 " SubCode={%s}\n",
7906 ioc->name, log_info, originator_desc, code_desc,
7907 sub_code_desc);
7908 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007909 printk(MYIOC_s_INFO_FMT
7910 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7911 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007912 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007913 sas_loginfo.dw.subcode);
7914 else
7915 printk(MYIOC_s_INFO_FMT
7916 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7917 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007918 ioc->name, log_info, originator_desc,
7919 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007920}
7921
Linus Torvalds1da177e2005-04-16 15:20:36 -07007922/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007923/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007924 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7925 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007926 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007927 * @mf: Pointer to MPT request frame
7928 *
7929 * Refer to lsi/mpi.h.
7930 **/
7931static void
7932mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7933{
7934 Config_t *pReq = (Config_t *)mf;
7935 char extend_desc[EVENT_DESCR_STR_SZ];
7936 char *desc = NULL;
7937 u32 form;
7938 u8 page_type;
7939
7940 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7941 page_type = pReq->ExtPageType;
7942 else
7943 page_type = pReq->Header.PageType;
7944
7945 /*
7946 * ignore invalid page messages for GET_NEXT_HANDLE
7947 */
7948 form = le32_to_cpu(pReq->PageAddress);
7949 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7950 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7951 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7952 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7953 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7954 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7955 return;
7956 }
7957 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7958 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7959 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7960 return;
7961 }
7962
7963 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7964 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7965 page_type, pReq->Header.PageNumber, pReq->Action, form);
7966
7967 switch (ioc_status) {
7968
7969 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7970 desc = "Config Page Invalid Action";
7971 break;
7972
7973 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7974 desc = "Config Page Invalid Type";
7975 break;
7976
7977 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7978 desc = "Config Page Invalid Page";
7979 break;
7980
7981 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7982 desc = "Config Page Invalid Data";
7983 break;
7984
7985 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7986 desc = "Config Page No Defaults";
7987 break;
7988
7989 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7990 desc = "Config Page Can't Commit";
7991 break;
7992 }
7993
7994 if (!desc)
7995 return;
7996
Eric Moore29dd3602007-09-14 18:46:51 -06007997 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7998 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007999}
8000
8001/**
8002 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07008003 * @ioc: Pointer to MPT_ADAPTER structure
8004 * @ioc_status: U32 IOCStatus word from IOC
8005 * @mf: Pointer to MPT request frame
8006 *
8007 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008008 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07008009static void
Eric Moorec6c727a2007-01-29 09:44:54 -07008010mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008011{
8012 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06008013 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008014
8015 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07008016
8017/****************************************************************************/
8018/* Common IOCStatus values for all replies */
8019/****************************************************************************/
8020
Linus Torvalds1da177e2005-04-16 15:20:36 -07008021 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
8022 desc = "Invalid Function";
8023 break;
8024
8025 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
8026 desc = "Busy";
8027 break;
8028
8029 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
8030 desc = "Invalid SGL";
8031 break;
8032
8033 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
8034 desc = "Internal Error";
8035 break;
8036
8037 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
8038 desc = "Reserved";
8039 break;
8040
8041 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
8042 desc = "Insufficient Resources";
8043 break;
8044
8045 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
8046 desc = "Invalid Field";
8047 break;
8048
8049 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
8050 desc = "Invalid State";
8051 break;
8052
Eric Moorec6c727a2007-01-29 09:44:54 -07008053/****************************************************************************/
8054/* Config IOCStatus values */
8055/****************************************************************************/
8056
Linus Torvalds1da177e2005-04-16 15:20:36 -07008057 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8058 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8059 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8060 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8061 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8062 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008063 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008064 break;
8065
Eric Moorec6c727a2007-01-29 09:44:54 -07008066/****************************************************************************/
8067/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
8068/* */
8069/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
8070/* */
8071/****************************************************************************/
8072
Linus Torvalds1da177e2005-04-16 15:20:36 -07008073 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008074 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008075 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
8076 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
8077 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
8078 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008079 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008080 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008081 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008082 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008083 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008084 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07008085 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008086 break;
8087
Eric Moorec6c727a2007-01-29 09:44:54 -07008088/****************************************************************************/
8089/* SCSI Target values */
8090/****************************************************************************/
8091
8092 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
8093 desc = "Target: Priority IO";
8094 break;
8095
8096 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
8097 desc = "Target: Invalid Port";
8098 break;
8099
8100 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
8101 desc = "Target Invalid IO Index:";
8102 break;
8103
8104 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
8105 desc = "Target: Aborted";
8106 break;
8107
8108 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
8109 desc = "Target: No Conn Retryable";
8110 break;
8111
8112 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
8113 desc = "Target: No Connection";
8114 break;
8115
8116 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
8117 desc = "Target: Transfer Count Mismatch";
8118 break;
8119
8120 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
8121 desc = "Target: STS Data not Sent";
8122 break;
8123
8124 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
8125 desc = "Target: Data Offset Error";
8126 break;
8127
8128 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
8129 desc = "Target: Too Much Write Data";
8130 break;
8131
8132 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
8133 desc = "Target: IU Too Short";
8134 break;
8135
8136 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
8137 desc = "Target: ACK NAK Timeout";
8138 break;
8139
8140 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
8141 desc = "Target: Nak Received";
8142 break;
8143
8144/****************************************************************************/
8145/* Fibre Channel Direct Access values */
8146/****************************************************************************/
8147
8148 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
8149 desc = "FC: Aborted";
8150 break;
8151
8152 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
8153 desc = "FC: RX ID Invalid";
8154 break;
8155
8156 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
8157 desc = "FC: DID Invalid";
8158 break;
8159
8160 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
8161 desc = "FC: Node Logged Out";
8162 break;
8163
8164 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
8165 desc = "FC: Exchange Canceled";
8166 break;
8167
8168/****************************************************************************/
8169/* LAN values */
8170/****************************************************************************/
8171
8172 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
8173 desc = "LAN: Device not Found";
8174 break;
8175
8176 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
8177 desc = "LAN: Device Failure";
8178 break;
8179
8180 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
8181 desc = "LAN: Transmit Error";
8182 break;
8183
8184 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
8185 desc = "LAN: Transmit Aborted";
8186 break;
8187
8188 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
8189 desc = "LAN: Receive Error";
8190 break;
8191
8192 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
8193 desc = "LAN: Receive Aborted";
8194 break;
8195
8196 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
8197 desc = "LAN: Partial Packet";
8198 break;
8199
8200 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
8201 desc = "LAN: Canceled";
8202 break;
8203
8204/****************************************************************************/
8205/* Serial Attached SCSI values */
8206/****************************************************************************/
8207
8208 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
8209 desc = "SAS: SMP Request Failed";
8210 break;
8211
8212 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
8213 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07008214 break;
8215
8216 default:
8217 desc = "Others";
8218 break;
8219 }
Eric Moorec6c727a2007-01-29 09:44:54 -07008220
8221 if (!desc)
8222 return;
8223
Eric Moore29dd3602007-09-14 18:46:51 -06008224 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
8225 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008226}
8227
8228/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008229EXPORT_SYMBOL(mpt_attach);
8230EXPORT_SYMBOL(mpt_detach);
8231#ifdef CONFIG_PM
8232EXPORT_SYMBOL(mpt_resume);
8233EXPORT_SYMBOL(mpt_suspend);
8234#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07008235EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008236EXPORT_SYMBOL(mpt_register);
8237EXPORT_SYMBOL(mpt_deregister);
8238EXPORT_SYMBOL(mpt_event_register);
8239EXPORT_SYMBOL(mpt_event_deregister);
8240EXPORT_SYMBOL(mpt_reset_register);
8241EXPORT_SYMBOL(mpt_reset_deregister);
8242EXPORT_SYMBOL(mpt_device_driver_register);
8243EXPORT_SYMBOL(mpt_device_driver_deregister);
8244EXPORT_SYMBOL(mpt_get_msg_frame);
8245EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05308246EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008247EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008248EXPORT_SYMBOL(mpt_send_handshake_request);
8249EXPORT_SYMBOL(mpt_verify_adapter);
8250EXPORT_SYMBOL(mpt_GetIocState);
8251EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008252EXPORT_SYMBOL(mpt_HardResetHandler);
8253EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008254EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008255EXPORT_SYMBOL(mpt_alloc_fw_memory);
8256EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02008257EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07008258EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008259
Linus Torvalds1da177e2005-04-16 15:20:36 -07008260/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008261/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008262 * fusion_init - Fusion MPT base driver initialization routine.
8263 *
8264 * Returns 0 for success, non-zero for failure.
8265 */
8266static int __init
8267fusion_init(void)
8268{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308269 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008270
8271 show_mptmod_ver(my_NAME, my_VERSION);
8272 printk(KERN_INFO COPYRIGHT "\n");
8273
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308274 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
8275 MptCallbacks[cb_idx] = NULL;
8276 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
8277 MptEvHandlers[cb_idx] = NULL;
8278 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008279 }
8280
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008281 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07008282 * EventNotification handling.
8283 */
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05308284 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008285
8286 /* Register for hard reset handling callbacks.
8287 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05308288 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008289
8290#ifdef CONFIG_PROC_FS
8291 (void) procmpt_create();
8292#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008293 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008294}
8295
8296/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008297/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008298 * fusion_exit - Perform driver unload cleanup.
8299 *
8300 * This routine frees all resources associated with each MPT adapter
8301 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
8302 */
8303static void __exit
8304fusion_exit(void)
8305{
8306
Linus Torvalds1da177e2005-04-16 15:20:36 -07008307 mpt_reset_deregister(mpt_base_index);
8308
8309#ifdef CONFIG_PROC_FS
8310 procmpt_destroy();
8311#endif
8312}
8313
Linus Torvalds1da177e2005-04-16 15:20:36 -07008314module_init(fusion_init);
8315module_exit(fusion_exit);