blob: 610e914abe6cfc92bd83b097455f8f2f2e3b5cef [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
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301018 (lower_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301019 pSge->Address.High = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301020 (upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301021 pSge->FlagsLength = cpu_to_le32
1022 ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1023}
1024
1025/**
Randy Dunlap9cf46a32009-06-13 19:37:18 -07001026 * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr (1078 workaround).
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301027 * @pAddr: virtual address for SGE
1028 * @flagslength: SGE flags and data transfer length
1029 * @dma_addr: Physical address
1030 *
1031 * This routine places a MPT request frame back on the MPT adapter's
1032 * FreeQ.
1033 **/
1034static void
1035mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1036{
1037 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1038 u32 tmp;
1039
1040 pSge->Address.Low = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301041 (lower_32_bits(dma_addr));
1042 tmp = (u32)(upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301043
1044 /*
1045 * 1078 errata workaround for the 36GB limitation
1046 */
1047 if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {
1048 flagslength |=
1049 MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
1050 tmp |= (1<<31);
1051 if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
1052 printk(KERN_DEBUG "1078 P0M2 addressing for "
1053 "addr = 0x%llx len = %d\n",
1054 (unsigned long long)dma_addr,
1055 MPI_SGE_LENGTH(flagslength));
1056 }
1057
1058 pSge->Address.High = cpu_to_le32(tmp);
1059 pSge->FlagsLength = cpu_to_le32(
1060 (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1061}
1062
1063/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1064/**
1065 * mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
1066 * @pAddr: virtual address for SGE
1067 * @next: nextChainOffset value (u32's)
1068 * @length: length of next SGL segment
1069 * @dma_addr: Physical address
1070 *
1071 */
1072static void
1073mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1074{
1075 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
1076 pChain->Length = cpu_to_le16(length);
1077 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
1078 pChain->NextChainOffset = next;
1079 pChain->Address = cpu_to_le32(dma_addr);
1080}
1081
1082/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1083/**
1084 * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
1085 * @pAddr: virtual address for SGE
1086 * @next: nextChainOffset value (u32's)
1087 * @length: length of next SGL segment
1088 * @dma_addr: Physical address
1089 *
1090 */
1091static void
1092mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1093{
1094 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 u32 tmp = dma_addr & 0xFFFFFFFF;
1096
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301097 pChain->Length = cpu_to_le16(length);
1098 pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
1099 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301101 pChain->NextChainOffset = next;
1102
1103 pChain->Address.Low = cpu_to_le32(tmp);
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301104 tmp = (u32)(upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301105 pChain->Address.High = cpu_to_le32(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106}
1107
1108/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1109/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001110 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301111 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 * @ioc: Pointer to MPT adapter structure
1113 * @reqBytes: Size of the request in bytes
1114 * @req: Pointer to MPT request frame
1115 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1116 *
1117 * This routine is used exclusively to send MptScsiTaskMgmt
1118 * requests since they are required to be sent via doorbell handshake.
1119 *
1120 * NOTE: It is the callers responsibility to byte-swap fields in the
1121 * request which are greater than 1 byte in size.
1122 *
1123 * Returns 0 for success, non-zero for failure.
1124 */
1125int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301126mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127{
Eric Moorecd2c6192007-01-29 09:47:47 -07001128 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 u8 *req_as_bytes;
1130 int ii;
1131
1132 /* State is known to be good upon entering
1133 * this function so issue the bus reset
1134 * request.
1135 */
1136
1137 /*
1138 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1139 * setting cb_idx/req_idx. But ONLY if this request
1140 * is in proper (pre-alloc'd) request buffer range...
1141 */
1142 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1143 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1144 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1145 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301146 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 }
1148
1149 /* Make sure there are no doorbells */
1150 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001151
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1153 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1154 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1155
1156 /* Wait for IOC doorbell int */
1157 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1158 return ii;
1159 }
1160
1161 /* Read doorbell and check for active bit */
1162 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1163 return -5;
1164
Eric Moore29dd3602007-09-14 18:46:51 -06001165 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001166 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167
1168 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1169
1170 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1171 return -2;
1172 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001173
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 /* Send request via doorbell handshake */
1175 req_as_bytes = (u8 *) req;
1176 for (ii = 0; ii < reqBytes/4; ii++) {
1177 u32 word;
1178
1179 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1180 (req_as_bytes[(ii*4) + 1] << 8) |
1181 (req_as_bytes[(ii*4) + 2] << 16) |
1182 (req_as_bytes[(ii*4) + 3] << 24));
1183 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1184 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1185 r = -3;
1186 break;
1187 }
1188 }
1189
1190 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1191 r = 0;
1192 else
1193 r = -4;
1194
1195 /* Make sure there are no doorbells */
1196 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001197
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 return r;
1199}
1200
1201/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1202/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001203 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001204 * @ioc: Pointer to MPT adapter structure
1205 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001206 * @sleepFlag: Specifies whether the process can sleep
1207 *
1208 * Provides mechanism for the host driver to control the IOC's
1209 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001210 *
1211 * Access Control Value - bits[15:12]
1212 * 0h Reserved
1213 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1214 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1215 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1216 *
1217 * Returns 0 for success, non-zero for failure.
1218 */
1219
1220static int
1221mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1222{
1223 int r = 0;
1224
1225 /* return if in use */
1226 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1227 & MPI_DOORBELL_ACTIVE)
1228 return -1;
1229
1230 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1231
1232 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1233 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1234 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1235 (access_control_value<<12)));
1236
1237 /* Wait for IOC to clear Doorbell Status bit */
1238 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1239 return -2;
1240 }else
1241 return 0;
1242}
1243
1244/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1245/**
1246 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001247 * @ioc: Pointer to pointer to IOC adapter
1248 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001249 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001250 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001251 * Returns 0 for success, non-zero for failure.
1252 */
1253static int
1254mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1255{
1256 char *psge;
1257 int flags_length;
1258 u32 host_page_buffer_sz=0;
1259
1260 if(!ioc->HostPageBuffer) {
1261
1262 host_page_buffer_sz =
1263 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1264
1265 if(!host_page_buffer_sz)
1266 return 0; /* fw doesn't need any host buffers */
1267
1268 /* spin till we get enough memory */
1269 while(host_page_buffer_sz > 0) {
1270
1271 if((ioc->HostPageBuffer = pci_alloc_consistent(
1272 ioc->pcidev,
1273 host_page_buffer_sz,
1274 &ioc->HostPageBuffer_dma)) != NULL) {
1275
Prakash, Sathya436ace72007-07-24 15:42:08 +05301276 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001277 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001278 ioc->name, ioc->HostPageBuffer,
1279 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001280 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001281 ioc->alloc_total += host_page_buffer_sz;
1282 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1283 break;
1284 }
1285
1286 host_page_buffer_sz -= (4*1024);
1287 }
1288 }
1289
1290 if(!ioc->HostPageBuffer) {
1291 printk(MYIOC_s_ERR_FMT
1292 "Failed to alloc memory for host_page_buffer!\n",
1293 ioc->name);
1294 return -999;
1295 }
1296
1297 psge = (char *)&ioc_init->HostPageBufferSGE;
1298 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1299 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001300 MPI_SGE_FLAGS_HOST_TO_IOC |
1301 MPI_SGE_FLAGS_END_OF_BUFFER;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001302 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1303 flags_length |= ioc->HostPageBuffer_sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301304 ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001305 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1306
1307return 0;
1308}
1309
1310/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1311/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001312 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 * @iocid: IOC unique identifier (integer)
1314 * @iocpp: Pointer to pointer to IOC adapter
1315 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001316 * Given a unique IOC identifier, set pointer to the associated MPT
1317 * adapter structure.
1318 *
1319 * Returns iocid and sets iocpp if iocid is found.
1320 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 */
1322int
1323mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1324{
1325 MPT_ADAPTER *ioc;
1326
1327 list_for_each_entry(ioc,&ioc_list,list) {
1328 if (ioc->id == iocid) {
1329 *iocpp =ioc;
1330 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001333
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 *iocpp = NULL;
1335 return -1;
1336}
1337
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301338/**
1339 * mpt_get_product_name - returns product string
1340 * @vendor: pci vendor id
1341 * @device: pci device id
1342 * @revision: pci revision id
1343 * @prod_name: string returned
1344 *
1345 * Returns product string displayed when driver loads,
1346 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1347 *
1348 **/
1349static void
1350mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1351{
1352 char *product_str = NULL;
1353
1354 if (vendor == PCI_VENDOR_ID_BROCADE) {
1355 switch (device)
1356 {
1357 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1358 switch (revision)
1359 {
1360 case 0x00:
1361 product_str = "BRE040 A0";
1362 break;
1363 case 0x01:
1364 product_str = "BRE040 A1";
1365 break;
1366 default:
1367 product_str = "BRE040";
1368 break;
1369 }
1370 break;
1371 }
1372 goto out;
1373 }
1374
1375 switch (device)
1376 {
1377 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1378 product_str = "LSIFC909 B1";
1379 break;
1380 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1381 product_str = "LSIFC919 B0";
1382 break;
1383 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1384 product_str = "LSIFC929 B0";
1385 break;
1386 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1387 if (revision < 0x80)
1388 product_str = "LSIFC919X A0";
1389 else
1390 product_str = "LSIFC919XL A1";
1391 break;
1392 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1393 if (revision < 0x80)
1394 product_str = "LSIFC929X A0";
1395 else
1396 product_str = "LSIFC929XL A1";
1397 break;
1398 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1399 product_str = "LSIFC939X A1";
1400 break;
1401 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1402 product_str = "LSIFC949X A1";
1403 break;
1404 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1405 switch (revision)
1406 {
1407 case 0x00:
1408 product_str = "LSIFC949E A0";
1409 break;
1410 case 0x01:
1411 product_str = "LSIFC949E A1";
1412 break;
1413 default:
1414 product_str = "LSIFC949E";
1415 break;
1416 }
1417 break;
1418 case MPI_MANUFACTPAGE_DEVID_53C1030:
1419 switch (revision)
1420 {
1421 case 0x00:
1422 product_str = "LSI53C1030 A0";
1423 break;
1424 case 0x01:
1425 product_str = "LSI53C1030 B0";
1426 break;
1427 case 0x03:
1428 product_str = "LSI53C1030 B1";
1429 break;
1430 case 0x07:
1431 product_str = "LSI53C1030 B2";
1432 break;
1433 case 0x08:
1434 product_str = "LSI53C1030 C0";
1435 break;
1436 case 0x80:
1437 product_str = "LSI53C1030T A0";
1438 break;
1439 case 0x83:
1440 product_str = "LSI53C1030T A2";
1441 break;
1442 case 0x87:
1443 product_str = "LSI53C1030T A3";
1444 break;
1445 case 0xc1:
1446 product_str = "LSI53C1020A A1";
1447 break;
1448 default:
1449 product_str = "LSI53C1030";
1450 break;
1451 }
1452 break;
1453 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1454 switch (revision)
1455 {
1456 case 0x03:
1457 product_str = "LSI53C1035 A2";
1458 break;
1459 case 0x04:
1460 product_str = "LSI53C1035 B0";
1461 break;
1462 default:
1463 product_str = "LSI53C1035";
1464 break;
1465 }
1466 break;
1467 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1468 switch (revision)
1469 {
1470 case 0x00:
1471 product_str = "LSISAS1064 A1";
1472 break;
1473 case 0x01:
1474 product_str = "LSISAS1064 A2";
1475 break;
1476 case 0x02:
1477 product_str = "LSISAS1064 A3";
1478 break;
1479 case 0x03:
1480 product_str = "LSISAS1064 A4";
1481 break;
1482 default:
1483 product_str = "LSISAS1064";
1484 break;
1485 }
1486 break;
1487 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1488 switch (revision)
1489 {
1490 case 0x00:
1491 product_str = "LSISAS1064E A0";
1492 break;
1493 case 0x01:
1494 product_str = "LSISAS1064E B0";
1495 break;
1496 case 0x02:
1497 product_str = "LSISAS1064E B1";
1498 break;
1499 case 0x04:
1500 product_str = "LSISAS1064E B2";
1501 break;
1502 case 0x08:
1503 product_str = "LSISAS1064E B3";
1504 break;
1505 default:
1506 product_str = "LSISAS1064E";
1507 break;
1508 }
1509 break;
1510 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1511 switch (revision)
1512 {
1513 case 0x00:
1514 product_str = "LSISAS1068 A0";
1515 break;
1516 case 0x01:
1517 product_str = "LSISAS1068 B0";
1518 break;
1519 case 0x02:
1520 product_str = "LSISAS1068 B1";
1521 break;
1522 default:
1523 product_str = "LSISAS1068";
1524 break;
1525 }
1526 break;
1527 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1528 switch (revision)
1529 {
1530 case 0x00:
1531 product_str = "LSISAS1068E A0";
1532 break;
1533 case 0x01:
1534 product_str = "LSISAS1068E B0";
1535 break;
1536 case 0x02:
1537 product_str = "LSISAS1068E B1";
1538 break;
1539 case 0x04:
1540 product_str = "LSISAS1068E B2";
1541 break;
1542 case 0x08:
1543 product_str = "LSISAS1068E B3";
1544 break;
1545 default:
1546 product_str = "LSISAS1068E";
1547 break;
1548 }
1549 break;
1550 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1551 switch (revision)
1552 {
1553 case 0x00:
1554 product_str = "LSISAS1078 A0";
1555 break;
1556 case 0x01:
1557 product_str = "LSISAS1078 B0";
1558 break;
1559 case 0x02:
1560 product_str = "LSISAS1078 C0";
1561 break;
1562 case 0x03:
1563 product_str = "LSISAS1078 C1";
1564 break;
1565 case 0x04:
1566 product_str = "LSISAS1078 C2";
1567 break;
1568 default:
1569 product_str = "LSISAS1078";
1570 break;
1571 }
1572 break;
1573 }
1574
1575 out:
1576 if (product_str)
1577 sprintf(prod_name, "%s", product_str);
1578}
1579
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301580/**
1581 * mpt_mapresources - map in memory mapped io
1582 * @ioc: Pointer to pointer to IOC adapter
1583 *
1584 **/
1585static int
1586mpt_mapresources(MPT_ADAPTER *ioc)
1587{
1588 u8 __iomem *mem;
1589 int ii;
1590 unsigned long mem_phys;
1591 unsigned long port;
1592 u32 msize;
1593 u32 psize;
1594 u8 revision;
1595 int r = -ENODEV;
1596 struct pci_dev *pdev;
1597
1598 pdev = ioc->pcidev;
1599 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1600 if (pci_enable_device_mem(pdev)) {
1601 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1602 "failed\n", ioc->name);
1603 return r;
1604 }
1605 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1606 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1607 "MEM failed\n", ioc->name);
1608 return r;
1609 }
1610
1611 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1612
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301613 if (sizeof(dma_addr_t) > 4) {
1614 const uint64_t required_mask = dma_get_required_mask
1615 (&pdev->dev);
1616 if (required_mask > DMA_BIT_MASK(32)
1617 && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
1618 && !pci_set_consistent_dma_mask(pdev,
1619 DMA_BIT_MASK(64))) {
1620 ioc->dma_mask = DMA_BIT_MASK(64);
1621 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1622 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1623 ioc->name));
1624 } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1625 && !pci_set_consistent_dma_mask(pdev,
1626 DMA_BIT_MASK(32))) {
1627 ioc->dma_mask = DMA_BIT_MASK(32);
1628 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1629 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1630 ioc->name));
1631 } else {
1632 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1633 ioc->name, pci_name(pdev));
1634 return r;
1635 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301636 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301637 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1638 && !pci_set_consistent_dma_mask(pdev,
1639 DMA_BIT_MASK(32))) {
1640 ioc->dma_mask = DMA_BIT_MASK(32);
1641 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1642 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1643 ioc->name));
1644 } else {
1645 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1646 ioc->name, pci_name(pdev));
1647 return r;
1648 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301649 }
1650
1651 mem_phys = msize = 0;
1652 port = psize = 0;
1653 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1654 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1655 if (psize)
1656 continue;
1657 /* Get I/O space! */
1658 port = pci_resource_start(pdev, ii);
1659 psize = pci_resource_len(pdev, ii);
1660 } else {
1661 if (msize)
1662 continue;
1663 /* Get memmap */
1664 mem_phys = pci_resource_start(pdev, ii);
1665 msize = pci_resource_len(pdev, ii);
1666 }
1667 }
1668 ioc->mem_size = msize;
1669
1670 mem = NULL;
1671 /* Get logical ptr for PciMem0 space */
1672 /*mem = ioremap(mem_phys, msize);*/
1673 mem = ioremap(mem_phys, msize);
1674 if (mem == NULL) {
1675 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1676 " memory!\n", ioc->name);
1677 return -EINVAL;
1678 }
1679 ioc->memmap = mem;
1680 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n",
1681 ioc->name, mem, mem_phys));
1682
1683 ioc->mem_phys = mem_phys;
1684 ioc->chip = (SYSIF_REGS __iomem *)mem;
1685
1686 /* Save Port IO values in case we need to do downloadboot */
1687 ioc->pio_mem_phys = port;
1688 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1689
1690 return 0;
1691}
1692
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001694/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001695 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001697 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 *
1699 * This routine performs all the steps necessary to bring the IOC of
1700 * a MPT adapter to a OPERATIONAL state. This includes registering
1701 * memory regions, registering the interrupt, and allocating request
1702 * and reply memory pools.
1703 *
1704 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1705 * MPT adapter.
1706 *
1707 * Returns 0 for success, non-zero for failure.
1708 *
1709 * TODO: Add support for polled controllers
1710 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001711int
1712mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713{
1714 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301715 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 u8 revision;
1718 u8 pcixcmd;
1719 static int mpt_ids = 0;
1720#ifdef CONFIG_PROC_FS
1721 struct proc_dir_entry *dent, *ent;
1722#endif
1723
Jesper Juhl56876192007-08-10 14:50:51 -07001724 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1725 if (ioc == NULL) {
1726 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1727 return -ENOMEM;
1728 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301729
Eric Moore29dd3602007-09-14 18:46:51 -06001730 ioc->id = mpt_ids++;
1731 sprintf(ioc->name, "ioc%d", ioc->id);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301732 dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Jesper Juhl56876192007-08-10 14:50:51 -07001733
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301734 /*
1735 * set initial debug level
1736 * (refer to mptdebug.h)
1737 *
1738 */
1739 ioc->debug_level = mpt_debug_level;
1740 if (mpt_debug_level)
1741 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301742
Eric Moore29dd3602007-09-14 18:46:51 -06001743 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001744
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301745 ioc->pcidev = pdev;
1746 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001747 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 return r;
1749 }
1750
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301751 /*
1752 * Setting up proper handlers for scatter gather handling
1753 */
1754 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
1755 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
1756 ioc->add_sge = &mpt_add_sge_64bit_1078;
1757 else
1758 ioc->add_sge = &mpt_add_sge_64bit;
1759 ioc->add_chain = &mpt_add_chain_64bit;
1760 ioc->sg_addr_size = 8;
1761 } else {
1762 ioc->add_sge = &mpt_add_sge;
1763 ioc->add_chain = &mpt_add_chain;
1764 ioc->sg_addr_size = 4;
1765 }
1766 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
1767
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 ioc->alloc_total = sizeof(MPT_ADAPTER);
1769 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1770 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001771
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 ioc->pcidev = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301774 spin_lock_init(&ioc->taskmgmt_lock);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05301775 mutex_init(&ioc->internal_cmds.mutex);
1776 init_completion(&ioc->internal_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301777 mutex_init(&ioc->mptbase_cmds.mutex);
1778 init_completion(&ioc->mptbase_cmds.done);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301779 mutex_init(&ioc->taskmgmt_cmds.mutex);
1780 init_completion(&ioc->taskmgmt_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301781
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 /* Initialize the event logging.
1783 */
1784 ioc->eventTypes = 0; /* None */
1785 ioc->eventContext = 0;
1786 ioc->eventLogSize = 0;
1787 ioc->events = NULL;
1788
1789#ifdef MFCNT
1790 ioc->mfcnt = 0;
1791#endif
1792
Kashyap, Desai2f187862009-05-29 16:52:37 +05301793 ioc->sh = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 ioc->cached_fw = NULL;
1795
1796 /* Initilize SCSI Config Data structure
1797 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001798 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799
Michael Reed05e8ec12006-01-13 14:31:54 -06001800 /* Initialize the fc rport list head.
1801 */
1802 INIT_LIST_HEAD(&ioc->fc_rports);
1803
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 /* Find lookup slot. */
1805 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001806
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301807
1808 /* Initialize workqueue */
1809 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301810
Kashyap, Desai2f187862009-05-29 16:52:37 +05301811 snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN,
Kay Sieversaab0de22008-05-02 06:02:41 +02001812 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301813 ioc->reset_work_q =
1814 create_singlethread_workqueue(ioc->reset_work_q_name);
1815 if (!ioc->reset_work_q) {
1816 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1817 ioc->name);
1818 pci_release_selected_regions(pdev, ioc->bars);
1819 kfree(ioc);
1820 return -ENOMEM;
1821 }
1822
Eric Moore29dd3602007-09-14 18:46:51 -06001823 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1824 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301826 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1827 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1828
1829 switch (pdev->device)
1830 {
1831 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1832 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1833 ioc->errata_flag_1064 = 1;
1834 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1835 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1836 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1837 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301839 break;
1840
1841 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 /* 929X Chip Fix. Set Split transactions level
1844 * for PCIX. Set MOST bits to zero.
1845 */
1846 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1847 pcixcmd &= 0x8F;
1848 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1849 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 /* 929XL Chip Fix. Set MMRBC to 0x08.
1851 */
1852 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1853 pcixcmd |= 0x08;
1854 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1855 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301857 break;
1858
1859 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 /* 919X Chip Fix. Set Split transactions level
1861 * for PCIX. Set MOST bits to zero.
1862 */
1863 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1864 pcixcmd &= 0x8F;
1865 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001866 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301867 break;
1868
1869 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 /* 1030 Chip Fix. Disable Split transactions
1871 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1872 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 if (revision < C0_1030) {
1874 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1875 pcixcmd &= 0x8F;
1876 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1877 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301878
1879 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001880 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301881 break;
1882
1883 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1884 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001885 ioc->errata_flag_1064 = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301886 ioc->bus_type = SAS;
1887 break;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301888
1889 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1890 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1891 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001892 ioc->bus_type = SAS;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301893 break;
Eric Moore87cf8982006-06-27 16:09:26 -06001894 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301896
Kashyap, Desaie3829682009-01-08 14:27:16 +05301897 switch (ioc->bus_type) {
1898
1899 case SAS:
1900 ioc->msi_enable = mpt_msi_enable_sas;
1901 break;
1902
1903 case SPI:
1904 ioc->msi_enable = mpt_msi_enable_spi;
1905 break;
1906
1907 case FC:
1908 ioc->msi_enable = mpt_msi_enable_fc;
1909 break;
1910
1911 default:
1912 ioc->msi_enable = 0;
1913 break;
1914 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001915 if (ioc->errata_flag_1064)
1916 pci_disable_io_access(pdev);
1917
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 spin_lock_init(&ioc->FreeQlock);
1919
1920 /* Disable all! */
1921 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1922 ioc->active = 0;
1923 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1924
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301925 /* Set IOC ptr in the pcidev's driver data. */
1926 pci_set_drvdata(ioc->pcidev, ioc);
1927
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 /* Set lookup ptr. */
1929 list_add_tail(&ioc->list, &ioc_list);
1930
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001931 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 */
1933 mpt_detect_bound_ports(ioc, pdev);
1934
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301935 INIT_LIST_HEAD(&ioc->fw_event_list);
1936 spin_lock_init(&ioc->fw_event_lock);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301937 snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301938 ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
1939
James Bottomleyc92f2222006-03-01 09:02:49 -06001940 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1941 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001942 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1943 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001944
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001946 if (ioc->alt_ioc)
1947 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301948 iounmap(ioc->memmap);
1949 if (r != -5)
1950 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301951
1952 destroy_workqueue(ioc->reset_work_q);
1953 ioc->reset_work_q = NULL;
1954
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 kfree(ioc);
1956 pci_set_drvdata(pdev, NULL);
1957 return r;
1958 }
1959
1960 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001961 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301962 if(MptDeviceDriverHandlers[cb_idx] &&
1963 MptDeviceDriverHandlers[cb_idx]->probe) {
1964 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 }
1966 }
1967
1968#ifdef CONFIG_PROC_FS
1969 /*
1970 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1971 */
1972 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1973 if (dent) {
1974 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1975 if (ent) {
1976 ent->read_proc = procmpt_iocinfo_read;
1977 ent->data = ioc;
1978 }
1979 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1980 if (ent) {
1981 ent->read_proc = procmpt_summary_read;
1982 ent->data = ioc;
1983 }
1984 }
1985#endif
1986
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301987 if (!ioc->alt_ioc)
1988 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1989 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1990
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 return 0;
1992}
1993
1994/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001995/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001996 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 */
1999
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002000void
2001mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002{
2003 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2004 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302005 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302006 unsigned long flags;
2007 struct workqueue_struct *wq;
2008
2009 /*
2010 * Stop polling ioc for fault condition
2011 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302012 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302013 wq = ioc->reset_work_q;
2014 ioc->reset_work_q = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302015 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302016 cancel_delayed_work(&ioc->fault_reset_work);
2017 destroy_workqueue(wq);
2018
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05302019 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2020 wq = ioc->fw_event_q;
2021 ioc->fw_event_q = NULL;
2022 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2023 destroy_workqueue(wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024
2025 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2026 remove_proc_entry(pname, NULL);
2027 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2028 remove_proc_entry(pname, NULL);
2029 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2030 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002031
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002033 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302034 if(MptDeviceDriverHandlers[cb_idx] &&
2035 MptDeviceDriverHandlers[cb_idx]->remove) {
2036 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 }
2038 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002039
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 /* Disable interrupts! */
2041 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2042
2043 ioc->active = 0;
2044 synchronize_irq(pdev->irq);
2045
2046 /* Clear any lingering interrupt */
2047 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2048
2049 CHIPREG_READ32(&ioc->chip->IntStatus);
2050
2051 mpt_adapter_dispose(ioc);
2052
2053 pci_set_drvdata(pdev, NULL);
2054}
2055
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056/**************************************************************************
2057 * Power Management
2058 */
2059#ifdef CONFIG_PM
2060/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002061/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002062 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002063 * @pdev: Pointer to pci_dev structure
2064 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002066int
2067mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068{
2069 u32 device_state;
2070 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302072 device_state = pci_choose_state(pdev, state);
2073 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2074 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2075 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076
2077 /* put ioc into READY_STATE */
2078 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2079 printk(MYIOC_s_ERR_FMT
2080 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2081 }
2082
2083 /* disable interrupts */
2084 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2085 ioc->active = 0;
2086
2087 /* Clear any lingering interrupt */
2088 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2089
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302090 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002091 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302092 pci_disable_msi(ioc->pcidev);
2093 ioc->pci_irq = -1;
2094 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302096 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 return 0;
2099}
2100
2101/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002102/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002103 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002104 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002106int
2107mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108{
2109 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2110 u32 device_state = pdev->current_state;
2111 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302112 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002113
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302114 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2115 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2116 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302118 pci_set_power_state(pdev, PCI_D0);
2119 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302121 ioc->pcidev = pdev;
2122 err = mpt_mapresources(ioc);
2123 if (err)
2124 return err;
2125
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302126 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2127 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2128 ioc->add_sge = &mpt_add_sge_64bit_1078;
2129 else
2130 ioc->add_sge = &mpt_add_sge_64bit;
2131 ioc->add_chain = &mpt_add_chain_64bit;
2132 ioc->sg_addr_size = 8;
2133 } else {
2134
2135 ioc->add_sge = &mpt_add_sge;
2136 ioc->add_chain = &mpt_add_chain;
2137 ioc->sg_addr_size = 4;
2138 }
2139 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2140
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302141 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2142 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2143 CHIPREG_READ32(&ioc->chip->Doorbell));
2144
2145 /*
2146 * Errata workaround for SAS pci express:
2147 * Upon returning to the D0 state, the contents of the doorbell will be
2148 * stale data, and this will incorrectly signal to the host driver that
2149 * the firmware is ready to process mpt commands. The workaround is
2150 * to issue a diagnostic reset.
2151 */
2152 if (ioc->bus_type == SAS && (pdev->device ==
2153 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2154 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2155 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2156 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2157 ioc->name);
2158 goto out;
2159 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302160 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161
2162 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302163 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2164 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2165 CAN_SLEEP);
2166 if (recovery_state != 0)
2167 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2168 "error:[%x]\n", ioc->name, recovery_state);
2169 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302171 "pci-resume: success\n", ioc->name);
2172 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302174
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175}
2176#endif
2177
James Bottomley4ff42a62006-05-17 18:06:52 -05002178static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302179mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002180{
2181 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2182 ioc->bus_type != SPI) ||
2183 (MptDriverClass[index] == MPTFC_DRIVER &&
2184 ioc->bus_type != FC) ||
2185 (MptDriverClass[index] == MPTSAS_DRIVER &&
2186 ioc->bus_type != SAS))
2187 /* make sure we only call the relevant reset handler
2188 * for the bus */
2189 return 0;
2190 return (MptResetHandlers[index])(ioc, reset_phase);
2191}
2192
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002194/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2196 * @ioc: Pointer to MPT adapter structure
2197 * @reason: Event word / reason
2198 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2199 *
2200 * This routine performs all the steps necessary to bring the IOC
2201 * to a OPERATIONAL state.
2202 *
2203 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2204 * MPT adapter.
2205 *
2206 * Returns:
2207 * 0 for success
2208 * -1 if failed to get board READY
2209 * -2 if READY but IOCFacts Failed
2210 * -3 if READY but PrimeIOCFifos Failed
2211 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302212 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302213 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 */
2215static int
2216mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2217{
2218 int hard_reset_done = 0;
2219 int alt_ioc_ready = 0;
2220 int hard;
2221 int rc=0;
2222 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 int ret = 0;
2224 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002225 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302226 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227
Eric Moore29dd3602007-09-14 18:46:51 -06002228 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2229 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230
2231 /* Disable reply interrupts (also blocks FreeQ) */
2232 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2233 ioc->active = 0;
2234
2235 if (ioc->alt_ioc) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302236 if (ioc->alt_ioc->active ||
2237 reason == MPT_HOSTEVENT_IOC_RECOVER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 reset_alt_ioc_active = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302239 /* Disable alt-IOC's reply interrupts
2240 * (and FreeQ) for a bit
2241 **/
2242 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2243 0xFFFFFFFF);
2244 ioc->alt_ioc->active = 0;
2245 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 }
2247
2248 hard = 1;
2249 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2250 hard = 0;
2251
2252 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2253 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002254 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2255 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256
2257 if (reset_alt_ioc_active && ioc->alt_ioc) {
2258 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002259 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2260 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002261 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 ioc->alt_ioc->active = 1;
2263 }
2264
2265 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302266 printk(MYIOC_s_WARN_FMT
2267 "NOT READY WARNING!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302269 ret = -1;
2270 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 }
2272
2273 /* hard_reset_done = 0 if a soft reset was performed
2274 * and 1 if a hard reset was performed.
2275 */
2276 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2277 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2278 alt_ioc_ready = 1;
2279 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05302280 printk(MYIOC_s_WARN_FMT
2281 ": alt-ioc Not ready WARNING!\n",
2282 ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 }
2284
2285 for (ii=0; ii<5; ii++) {
2286 /* Get IOC facts! Allow 5 retries */
2287 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2288 break;
2289 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002290
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291
2292 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002293 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2294 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 ret = -2;
2296 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2297 MptDisplayIocCapabilities(ioc);
2298 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002299
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 if (alt_ioc_ready) {
2301 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302302 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302303 "Initial Alt IocFacts failed rc=%x\n",
2304 ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 /* Retry - alt IOC was initialized once
2306 */
2307 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2308 }
2309 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302310 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002311 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 alt_ioc_ready = 0;
2313 reset_alt_ioc_active = 0;
2314 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2315 MptDisplayIocCapabilities(ioc->alt_ioc);
2316 }
2317 }
2318
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302319 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2320 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2321 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2322 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2323 IORESOURCE_IO);
2324 if (pci_enable_device(ioc->pcidev))
2325 return -5;
2326 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2327 "mpt"))
2328 return -5;
2329 }
2330
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002331 /*
2332 * Device is reset now. It must have de-asserted the interrupt line
2333 * (if it was asserted) and it should be safe to register for the
2334 * interrupt now.
2335 */
2336 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2337 ioc->pci_irq = -1;
2338 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302339 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002340 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002341 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302342 else
2343 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002344 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002345 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002346 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002347 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Kashyap, Desai2f187862009-05-29 16:52:37 +05302348 "interrupt %d!\n",
2349 ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302350 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002351 pci_disable_msi(ioc->pcidev);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302352 ret = -EBUSY;
2353 goto out;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002354 }
2355 irq_allocated = 1;
2356 ioc->pci_irq = ioc->pcidev->irq;
2357 pci_set_master(ioc->pcidev); /* ?? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302358 pci_set_drvdata(ioc->pcidev, ioc);
2359 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2360 "installed at interrupt %d\n", ioc->name,
2361 ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002362 }
2363 }
2364
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 /* Prime reply & request queues!
2366 * (mucho alloc's) Must be done prior to
2367 * init as upper addresses are needed for init.
2368 * If fails, continue with alt-ioc processing
2369 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302370 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
2371 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2373 ret = -3;
2374
2375 /* May need to check/upload firmware & data here!
2376 * If fails, continue with alt-ioc processing
2377 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302378 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
2379 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2381 ret = -4;
2382// NEW!
2383 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302384 printk(MYIOC_s_WARN_FMT
2385 ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002386 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 alt_ioc_ready = 0;
2388 reset_alt_ioc_active = 0;
2389 }
2390
2391 if (alt_ioc_ready) {
2392 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2393 alt_ioc_ready = 0;
2394 reset_alt_ioc_active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302395 printk(MYIOC_s_WARN_FMT
2396 ": alt-ioc: (%d) init failure WARNING!\n",
2397 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 }
2399 }
2400
2401 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2402 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302403 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002404 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405
2406 /* Controller is not operational, cannot do upload
2407 */
2408 if (ret == 0) {
2409 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002410 if (rc == 0) {
2411 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2412 /*
2413 * Maintain only one pointer to FW memory
2414 * so there will not be two attempt to
2415 * downloadboot onboard dual function
2416 * chips (mpt_adapter_disable,
2417 * mpt_diag_reset)
2418 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302419 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002420 "mpt_upload: alt_%s has cached_fw=%p \n",
2421 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302422 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002423 }
2424 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002425 printk(MYIOC_s_WARN_FMT
2426 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302427 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002428 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 }
2430 }
2431 }
2432
Kashyap, Desaifd761752009-05-29 16:39:06 +05302433 /* Enable MPT base driver management of EventNotification
2434 * and EventAck handling.
2435 */
2436 if ((ret == 0) && (!ioc->facts.EventState)) {
2437 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2438 "SendEventNotification\n",
2439 ioc->name));
2440 ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
2441 }
2442
2443 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2444 rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
2445
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 if (ret == 0) {
2447 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002448 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 ioc->active = 1;
2450 }
Kashyap, Desaifd761752009-05-29 16:39:06 +05302451 if (rc == 0) { /* alt ioc */
2452 if (reset_alt_ioc_active && ioc->alt_ioc) {
2453 /* (re)Enable alt-IOC! (reply interrupt) */
2454 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
2455 "reply irq re-enabled\n",
2456 ioc->alt_ioc->name));
2457 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2458 MPI_HIM_DIM);
2459 ioc->alt_ioc->active = 1;
2460 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 }
2462
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002464 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2466 * recursive scenario; GetLanConfigPages times out, timer expired
2467 * routine calls HardResetHandler, which calls into here again,
2468 * and we try GetLanConfigPages again...
2469 */
2470 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002471
2472 /*
2473 * Initalize link list for inactive raid volumes.
2474 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002475 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002476 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2477
Kashyap, Desai2f187862009-05-29 16:52:37 +05302478 switch (ioc->bus_type) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002479
Kashyap, Desai2f187862009-05-29 16:52:37 +05302480 case SAS:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002481 /* clear persistency table */
2482 if(ioc->facts.IOCExceptions &
2483 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2484 ret = mptbase_sas_persist_operation(ioc,
2485 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2486 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002487 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002488 }
2489
2490 /* Find IM volumes
2491 */
2492 mpt_findImVolumes(ioc);
2493
Kashyap, Desai2f187862009-05-29 16:52:37 +05302494 /* Check, and possibly reset, the coalescing value
2495 */
2496 mpt_read_ioc_pg_1(ioc);
2497
2498 break;
2499
2500 case FC:
2501 if ((ioc->pfacts[0].ProtocolFlags &
2502 MPI_PORTFACTS_PROTOCOL_LAN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2504 /*
2505 * Pre-fetch the ports LAN MAC address!
2506 * (LANPage1_t stuff)
2507 */
2508 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302509 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2510 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302511 "LanAddr = %02X:%02X:%02X"
2512 ":%02X:%02X:%02X\n",
2513 ioc->name, a[5], a[4],
2514 a[3], a[2], a[1], a[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302516 break;
2517
2518 case SPI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 /* Get NVRAM and adapter maximums from SPP 0 and 2
2520 */
2521 mpt_GetScsiPortSettings(ioc, 0);
2522
2523 /* Get version and length of SDP 1
2524 */
2525 mpt_readScsiDevicePageHeaders(ioc, 0);
2526
2527 /* Find IM volumes
2528 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002529 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 mpt_findImVolumes(ioc);
2531
2532 /* Check, and possibly reset, the coalescing value
2533 */
2534 mpt_read_ioc_pg_1(ioc);
2535
2536 mpt_read_ioc_pg_4(ioc);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302537
2538 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 }
2540
2541 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302542 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 }
2544
Eric Moore0ccdb002006-07-11 17:33:13 -06002545 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002546 if ((ret != 0) && irq_allocated) {
2547 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302548 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002549 pci_disable_msi(ioc->pcidev);
2550 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 return ret;
2552}
2553
2554/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002555/**
2556 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 * @ioc: Pointer to MPT adapter structure
2558 * @pdev: Pointer to (struct pci_dev) structure
2559 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002560 * Search for PCI bus/dev_function which matches
2561 * PCI bus/dev_function (+/-1) for newly discovered 929,
2562 * 929X, 1030 or 1035.
2563 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2565 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2566 */
2567static void
2568mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2569{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002570 struct pci_dev *peer=NULL;
2571 unsigned int slot = PCI_SLOT(pdev->devfn);
2572 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 MPT_ADAPTER *ioc_srch;
2574
Prakash, Sathya436ace72007-07-24 15:42:08 +05302575 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002576 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002577 ioc->name, pci_name(pdev), pdev->bus->number,
2578 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002579
2580 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2581 if (!peer) {
2582 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2583 if (!peer)
2584 return;
2585 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586
2587 list_for_each_entry(ioc_srch, &ioc_list, list) {
2588 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002589 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 /* Paranoia checks */
2591 if (ioc->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302592 printk(MYIOC_s_WARN_FMT
2593 "Oops, already bound (%s <==> %s)!\n",
2594 ioc->name, ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 break;
2596 } else if (ioc_srch->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302597 printk(MYIOC_s_WARN_FMT
2598 "Oops, already bound (%s <==> %s)!\n",
2599 ioc_srch->name, ioc_srch->name,
2600 ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 break;
2602 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302603 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2604 "FOUND! binding %s <==> %s\n",
2605 ioc->name, ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 ioc_srch->alt_ioc = ioc;
2607 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 }
2609 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002610 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611}
2612
2613/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002614/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002616 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 */
2618static void
2619mpt_adapter_disable(MPT_ADAPTER *ioc)
2620{
2621 int sz;
2622 int ret;
2623
2624 if (ioc->cached_fw != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302625 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2626 "%s: Pushing FW onto adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302627 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2628 ioc->cached_fw, CAN_SLEEP)) < 0) {
2629 printk(MYIOC_s_WARN_FMT
2630 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002631 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 }
2633 }
2634
Kashyap, Desai71278192009-05-29 16:53:14 +05302635 /*
2636 * Put the controller into ready state (if its not already)
2637 */
2638 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {
2639 if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
2640 CAN_SLEEP)) {
2641 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)
2642 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit "
2643 "reset failed to put ioc in ready state!\n",
2644 ioc->name, __func__);
2645 } else
2646 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset "
2647 "failed!\n", ioc->name, __func__);
2648 }
2649
2650
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 /* Disable adapter interrupts! */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302652 synchronize_irq(ioc->pcidev->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2654 ioc->active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302655
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 /* Clear any lingering interrupt */
2657 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302658 CHIPREG_READ32(&ioc->chip->IntStatus);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659
2660 if (ioc->alloc != NULL) {
2661 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002662 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2663 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 pci_free_consistent(ioc->pcidev, sz,
2665 ioc->alloc, ioc->alloc_dma);
2666 ioc->reply_frames = NULL;
2667 ioc->req_frames = NULL;
2668 ioc->alloc = NULL;
2669 ioc->alloc_total -= sz;
2670 }
2671
2672 if (ioc->sense_buf_pool != NULL) {
2673 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2674 pci_free_consistent(ioc->pcidev, sz,
2675 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2676 ioc->sense_buf_pool = NULL;
2677 ioc->alloc_total -= sz;
2678 }
2679
2680 if (ioc->events != NULL){
2681 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2682 kfree(ioc->events);
2683 ioc->events = NULL;
2684 ioc->alloc_total -= sz;
2685 }
2686
Prakash, Sathya984621b2008-01-11 14:42:17 +05302687 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002689 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002690 mpt_inactive_raid_list_free(ioc);
2691 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002692 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002693 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002694 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695
2696 if (ioc->spi_data.pIocPg4 != NULL) {
2697 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302698 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 ioc->spi_data.pIocPg4,
2700 ioc->spi_data.IocPg4_dma);
2701 ioc->spi_data.pIocPg4 = NULL;
2702 ioc->alloc_total -= sz;
2703 }
2704
2705 if (ioc->ReqToChain != NULL) {
2706 kfree(ioc->ReqToChain);
2707 kfree(ioc->RequestNB);
2708 ioc->ReqToChain = NULL;
2709 }
2710
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002711 kfree(ioc->ChainToChain);
2712 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002713
2714 if (ioc->HostPageBuffer != NULL) {
2715 if((ret = mpt_host_page_access_control(ioc,
2716 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002717 printk(MYIOC_s_ERR_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302718 ": %s: host page buffers free failed (%d)!\n",
2719 ioc->name, __func__, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002720 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302721 dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2722 "HostPageBuffer free @ %p, sz=%d bytes\n",
2723 ioc->name, ioc->HostPageBuffer,
2724 ioc->HostPageBuffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002725 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002726 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002727 ioc->HostPageBuffer = NULL;
2728 ioc->HostPageBuffer_sz = 0;
2729 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2730 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731
Kashyap, Desai2f187862009-05-29 16:52:37 +05302732 pci_set_drvdata(ioc->pcidev, NULL);
2733}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002735/**
2736 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 * @ioc: Pointer to MPT adapter structure
2738 *
2739 * This routine unregisters h/w resources and frees all alloc'd memory
2740 * associated with a MPT adapter structure.
2741 */
2742static void
2743mpt_adapter_dispose(MPT_ADAPTER *ioc)
2744{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002745 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002747 if (ioc == NULL)
2748 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002750 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002752 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002754 if (ioc->pci_irq != -1) {
2755 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302756 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002757 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002758 ioc->pci_irq = -1;
2759 }
2760
2761 if (ioc->memmap != NULL) {
2762 iounmap(ioc->memmap);
2763 ioc->memmap = NULL;
2764 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302766 pci_disable_device(ioc->pcidev);
2767 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2768
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002770 if (ioc->mtrr_reg > 0) {
2771 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002772 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002773 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774#endif
2775
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002776 /* Zap the adapter lookup ptr! */
2777 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002779 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002780 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2781 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002782
2783 if (ioc->alt_ioc)
2784 ioc->alt_ioc->alt_ioc = NULL;
2785
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002786 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787}
2788
2789/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002790/**
2791 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 * @ioc: Pointer to MPT adapter structure
2793 */
2794static void
2795MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2796{
2797 int i = 0;
2798
2799 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302800 if (ioc->prod_name)
2801 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 printk("Capabilities={");
2803
2804 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2805 printk("Initiator");
2806 i++;
2807 }
2808
2809 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2810 printk("%sTarget", i ? "," : "");
2811 i++;
2812 }
2813
2814 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2815 printk("%sLAN", i ? "," : "");
2816 i++;
2817 }
2818
2819#if 0
2820 /*
2821 * This would probably evoke more questions than it's worth
2822 */
2823 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2824 printk("%sLogBusAddr", i ? "," : "");
2825 i++;
2826 }
2827#endif
2828
2829 printk("}\n");
2830}
2831
2832/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002833/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2835 * @ioc: Pointer to MPT_ADAPTER structure
2836 * @force: Force hard KickStart of IOC
2837 * @sleepFlag: Specifies whether the process can sleep
2838 *
2839 * Returns:
2840 * 1 - DIAG reset and READY
2841 * 0 - READY initially OR soft reset and READY
2842 * -1 - Any failure on KickStart
2843 * -2 - Msg Unit Reset Failed
2844 * -3 - IO Unit Reset Failed
2845 * -4 - IOC owned by a PEER
2846 */
2847static int
2848MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2849{
2850 u32 ioc_state;
2851 int statefault = 0;
2852 int cntdn;
2853 int hard_reset_done = 0;
2854 int r;
2855 int ii;
2856 int whoinit;
2857
2858 /* Get current [raw] IOC state */
2859 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002860 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861
2862 /*
2863 * Check to see if IOC got left/stuck in doorbell handshake
2864 * grip of death. If so, hard reset the IOC.
2865 */
2866 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2867 statefault = 1;
2868 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2869 ioc->name);
2870 }
2871
2872 /* Is it already READY? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302873 if (!statefault &&
2874 ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) {
2875 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2876 "IOC is in READY state\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 return 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302878 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879
2880 /*
2881 * Check to see if IOC is in FAULT state.
2882 */
2883 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2884 statefault = 2;
2885 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002886 ioc->name);
2887 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2888 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889 }
2890
2891 /*
2892 * Hmmm... Did it get left operational?
2893 */
2894 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302895 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 ioc->name));
2897
2898 /* Check WhoInit.
2899 * If PCI Peer, exit.
2900 * Else, if no fault conditions are present, issue a MessageUnitReset
2901 * Else, fall through to KickStart case
2902 */
2903 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002904 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2905 "whoinit 0x%x statefault %d force %d\n",
2906 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 if (whoinit == MPI_WHOINIT_PCI_PEER)
2908 return -4;
2909 else {
2910 if ((statefault == 0 ) && (force == 0)) {
2911 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2912 return 0;
2913 }
2914 statefault = 3;
2915 }
2916 }
2917
2918 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2919 if (hard_reset_done < 0)
2920 return -1;
2921
2922 /*
2923 * Loop here waiting for IOC to come READY.
2924 */
2925 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002926 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927
2928 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2929 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2930 /*
2931 * BIOS or previous driver load left IOC in OP state.
2932 * Reset messaging FIFOs.
2933 */
2934 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2935 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2936 return -2;
2937 }
2938 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2939 /*
2940 * Something is wrong. Try to get IOC back
2941 * to a known state.
2942 */
2943 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2944 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2945 return -3;
2946 }
2947 }
2948
2949 ii++; cntdn--;
2950 if (!cntdn) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302951 printk(MYIOC_s_ERR_FMT
2952 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
2953 ioc->name, ioc_state, (int)((ii+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 return -ETIME;
2955 }
2956
2957 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002958 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 } else {
2960 mdelay (1); /* 1 msec delay */
2961 }
2962
2963 }
2964
2965 if (statefault < 3) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302966 printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name,
2967 statefault == 1 ? "stuck handshake" : "IOC FAULT");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 }
2969
2970 return hard_reset_done;
2971}
2972
2973/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002974/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 * mpt_GetIocState - Get the current state of a MPT adapter.
2976 * @ioc: Pointer to MPT_ADAPTER structure
2977 * @cooked: Request raw or cooked IOC state
2978 *
2979 * Returns all IOC Doorbell register bits if cooked==0, else just the
2980 * Doorbell bits in MPI_IOC_STATE_MASK.
2981 */
2982u32
2983mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2984{
2985 u32 s, sc;
2986
2987 /* Get! */
2988 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 sc = s & MPI_IOC_STATE_MASK;
2990
2991 /* Save! */
2992 ioc->last_state = sc;
2993
2994 return cooked ? sc : s;
2995}
2996
2997/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002998/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 * GetIocFacts - Send IOCFacts request to MPT adapter.
3000 * @ioc: Pointer to MPT_ADAPTER structure
3001 * @sleepFlag: Specifies whether the process can sleep
3002 * @reason: If recovery, only update facts.
3003 *
3004 * Returns 0 for success, non-zero for failure.
3005 */
3006static int
3007GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
3008{
3009 IOCFacts_t get_facts;
3010 IOCFactsReply_t *facts;
3011 int r;
3012 int req_sz;
3013 int reply_sz;
3014 int sz;
3015 u32 status, vv;
3016 u8 shiftFactor=1;
3017
3018 /* IOC *must* NOT be in RESET state! */
3019 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303020 printk(KERN_ERR MYNAM
3021 ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
3022 ioc->name, ioc->last_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 return -44;
3024 }
3025
3026 facts = &ioc->facts;
3027
3028 /* Destination (reply area)... */
3029 reply_sz = sizeof(*facts);
3030 memset(facts, 0, reply_sz);
3031
3032 /* Request area (get_facts on the stack right now!) */
3033 req_sz = sizeof(get_facts);
3034 memset(&get_facts, 0, req_sz);
3035
3036 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
3037 /* Assert: All other get_facts fields are zero! */
3038
Prakash, Sathya436ace72007-07-24 15:42:08 +05303039 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003040 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 ioc->name, req_sz, reply_sz));
3042
3043 /* No non-zero fields in the get_facts request are greater than
3044 * 1 byte in size, so we can just fire it off as is.
3045 */
3046 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3047 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3048 if (r != 0)
3049 return r;
3050
3051 /*
3052 * Now byte swap (GRRR) the necessary fields before any further
3053 * inspection of reply contents.
3054 *
3055 * But need to do some sanity checks on MsgLength (byte) field
3056 * to make sure we don't zero IOC's req_sz!
3057 */
3058 /* Did we get a valid reply? */
3059 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3060 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3061 /*
3062 * If not been here, done that, save off first WhoInit value
3063 */
3064 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3065 ioc->FirstWhoInit = facts->WhoInit;
3066 }
3067
3068 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3069 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3070 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3071 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3072 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003073 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074 /* CHECKME! IOCStatus, IOCLogInfo */
3075
3076 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3077 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3078
3079 /*
3080 * FC f/w version changed between 1.1 and 1.2
3081 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3082 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3083 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303084 if (facts->MsgVersion < MPI_VERSION_01_02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 /*
3086 * Handle old FC f/w style, convert to new...
3087 */
3088 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3089 facts->FWVersion.Word =
3090 ((oldv<<12) & 0xFF000000) |
3091 ((oldv<<8) & 0x000FFF00);
3092 } else
3093 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3094
3095 facts->ProductID = le16_to_cpu(facts->ProductID);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303096
Eric Mooreb506ade2007-01-29 09:45:37 -07003097 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3098 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3099 ioc->ir_firmware = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303100
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 facts->CurrentHostMfaHighAddr =
3102 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3103 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3104 facts->CurrentSenseBufferHighAddr =
3105 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3106 facts->CurReplyFrameSize =
3107 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003108 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109
3110 /*
3111 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3112 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3113 * to 14 in MPI-1.01.0x.
3114 */
3115 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
Kashyap, Desai2f187862009-05-29 16:52:37 +05303116 facts->MsgVersion > MPI_VERSION_01_00) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3118 }
3119
3120 sz = facts->FWImageSize;
3121 if ( sz & 0x01 )
3122 sz += 1;
3123 if ( sz & 0x02 )
3124 sz += 2;
3125 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003126
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 if (!facts->RequestFrameSize) {
3128 /* Something is wrong! */
3129 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3130 ioc->name);
3131 return -55;
3132 }
3133
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003134 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 vv = ((63 / (sz * 4)) + 1) & 0x03;
3136 ioc->NB_for_64_byte_frame = vv;
3137 while ( sz )
3138 {
3139 shiftFactor++;
3140 sz = sz >> 1;
3141 }
3142 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303143 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003144 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3145 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003146
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3148 /*
3149 * Set values for this IOC's request & reply frame sizes,
3150 * and request & reply queue depths...
3151 */
3152 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3153 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3154 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3155 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3156
Prakash, Sathya436ace72007-07-24 15:42:08 +05303157 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303159 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 ioc->name, ioc->req_sz, ioc->req_depth));
3161
3162 /* Get port facts! */
3163 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3164 return r;
3165 }
3166 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003167 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3169 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3170 RequestFrameSize)/sizeof(u32)));
3171 return -66;
3172 }
3173
3174 return 0;
3175}
3176
3177/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003178/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 * GetPortFacts - Send PortFacts request to MPT adapter.
3180 * @ioc: Pointer to MPT_ADAPTER structure
3181 * @portnum: Port number
3182 * @sleepFlag: Specifies whether the process can sleep
3183 *
3184 * Returns 0 for success, non-zero for failure.
3185 */
3186static int
3187GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3188{
3189 PortFacts_t get_pfacts;
3190 PortFactsReply_t *pfacts;
3191 int ii;
3192 int req_sz;
3193 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003194 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195
3196 /* IOC *must* NOT be in RESET state! */
3197 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003198 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3199 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 return -4;
3201 }
3202
3203 pfacts = &ioc->pfacts[portnum];
3204
3205 /* Destination (reply area)... */
3206 reply_sz = sizeof(*pfacts);
3207 memset(pfacts, 0, reply_sz);
3208
3209 /* Request area (get_pfacts on the stack right now!) */
3210 req_sz = sizeof(get_pfacts);
3211 memset(&get_pfacts, 0, req_sz);
3212
3213 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3214 get_pfacts.PortNumber = portnum;
3215 /* Assert: All other get_pfacts fields are zero! */
3216
Prakash, Sathya436ace72007-07-24 15:42:08 +05303217 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 ioc->name, portnum));
3219
3220 /* No non-zero fields in the get_pfacts request are greater than
3221 * 1 byte in size, so we can just fire it off as is.
3222 */
3223 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3224 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3225 if (ii != 0)
3226 return ii;
3227
3228 /* Did we get a valid reply? */
3229
3230 /* Now byte swap the necessary fields in the response. */
3231 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3232 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3233 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3234 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3235 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3236 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3237 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3238 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3239 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3240
Eric Moore793955f2007-01-29 09:42:20 -07003241 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3242 pfacts->MaxDevices;
3243 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3244 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3245
3246 /*
3247 * Place all the devices on channels
3248 *
3249 * (for debuging)
3250 */
3251 if (mpt_channel_mapping) {
3252 ioc->devices_per_bus = 1;
3253 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3254 }
3255
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 return 0;
3257}
3258
3259/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003260/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261 * SendIocInit - Send IOCInit request to MPT adapter.
3262 * @ioc: Pointer to MPT_ADAPTER structure
3263 * @sleepFlag: Specifies whether the process can sleep
3264 *
3265 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3266 *
3267 * Returns 0 for success, non-zero for failure.
3268 */
3269static int
3270SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3271{
3272 IOCInit_t ioc_init;
3273 MPIDefaultReply_t init_reply;
3274 u32 state;
3275 int r;
3276 int count;
3277 int cntdn;
3278
3279 memset(&ioc_init, 0, sizeof(ioc_init));
3280 memset(&init_reply, 0, sizeof(init_reply));
3281
3282 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3283 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3284
3285 /* If we are in a recovery mode and we uploaded the FW image,
3286 * then this pointer is not NULL. Skip the upload a second time.
3287 * Set this flag if cached_fw set for either IOC.
3288 */
3289 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3290 ioc->upload_fw = 1;
3291 else
3292 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303293 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3295
Eric Moore793955f2007-01-29 09:42:20 -07003296 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3297 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303298
Prakash, Sathya436ace72007-07-24 15:42:08 +05303299 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003300 ioc->name, ioc->facts.MsgVersion));
3301 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3302 // set MsgVersion and HeaderVersion host driver was built with
3303 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3304 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003306 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3307 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3308 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3309 return -99;
3310 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3312
Kashyap, Desai2f187862009-05-29 16:52:37 +05303313 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 /* Save the upper 32-bits of the request
3315 * (reply) and sense buffers.
3316 */
3317 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3318 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3319 } else {
3320 /* Force 32-bit addressing */
3321 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3322 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3323 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003324
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3326 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003327 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3328 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329
Prakash, Sathya436ace72007-07-24 15:42:08 +05303330 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 ioc->name, &ioc_init));
3332
3333 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3334 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003335 if (r != 0) {
3336 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339
3340 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003341 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 */
3343
Prakash, Sathya436ace72007-07-24 15:42:08 +05303344 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003346
3347 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3348 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003350 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351
3352 /* YIKES! SUPER IMPORTANT!!!
3353 * Poll IocState until _OPERATIONAL while IOC is doing
3354 * LoopInit and TargetDiscovery!
3355 */
3356 count = 0;
3357 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3358 state = mpt_GetIocState(ioc, 1);
3359 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3360 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003361 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362 } else {
3363 mdelay(1);
3364 }
3365
3366 if (!cntdn) {
3367 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3368 ioc->name, (int)((count+5)/HZ));
3369 return -9;
3370 }
3371
3372 state = mpt_GetIocState(ioc, 1);
3373 count++;
3374 }
Eric Moore29dd3602007-09-14 18:46:51 -06003375 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 ioc->name, count));
3377
Eric Mooreba856d32006-07-11 17:34:01 -06003378 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 return r;
3380}
3381
3382/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003383/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 * SendPortEnable - Send PortEnable request to MPT adapter port.
3385 * @ioc: Pointer to MPT_ADAPTER structure
3386 * @portnum: Port number to enable
3387 * @sleepFlag: Specifies whether the process can sleep
3388 *
3389 * Send PortEnable to bring IOC to OPERATIONAL state.
3390 *
3391 * Returns 0 for success, non-zero for failure.
3392 */
3393static int
3394SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3395{
3396 PortEnable_t port_enable;
3397 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003398 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 int req_sz;
3400 int reply_sz;
3401
3402 /* Destination... */
3403 reply_sz = sizeof(MPIDefaultReply_t);
3404 memset(&reply_buf, 0, reply_sz);
3405
3406 req_sz = sizeof(PortEnable_t);
3407 memset(&port_enable, 0, req_sz);
3408
3409 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3410 port_enable.PortNumber = portnum;
3411/* port_enable.ChainOffset = 0; */
3412/* port_enable.MsgFlags = 0; */
3413/* port_enable.MsgContext = 0; */
3414
Prakash, Sathya436ace72007-07-24 15:42:08 +05303415 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 ioc->name, portnum, &port_enable));
3417
3418 /* RAID FW may take a long time to enable
3419 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003420 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003421 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3422 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3423 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003424 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003425 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3426 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3427 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003429 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430}
3431
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003432/**
3433 * mpt_alloc_fw_memory - allocate firmware memory
3434 * @ioc: Pointer to MPT_ADAPTER structure
3435 * @size: total FW bytes
3436 *
3437 * If memory has already been allocated, the same (cached) value
3438 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303439 *
3440 * Return 0 if successfull, or non-zero for failure
3441 **/
3442int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3444{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303445 int rc;
3446
3447 if (ioc->cached_fw) {
3448 rc = 0; /* use already allocated memory */
3449 goto out;
3450 }
3451 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3453 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303454 rc = 0;
3455 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303457 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3458 if (!ioc->cached_fw) {
3459 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3460 ioc->name);
3461 rc = -1;
3462 } else {
3463 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3464 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3465 ioc->alloc_total += size;
3466 rc = 0;
3467 }
3468 out:
3469 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303471
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003472/**
3473 * mpt_free_fw_memory - free firmware memory
3474 * @ioc: Pointer to MPT_ADAPTER structure
3475 *
3476 * If alt_img is NULL, delete from ioc structure.
3477 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303478 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479void
3480mpt_free_fw_memory(MPT_ADAPTER *ioc)
3481{
3482 int sz;
3483
Prakash, Sathya984621b2008-01-11 14:42:17 +05303484 if (!ioc->cached_fw)
3485 return;
3486
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303488 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3489 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003490 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303491 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493}
3494
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003496/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3498 * @ioc: Pointer to MPT_ADAPTER structure
3499 * @sleepFlag: Specifies whether the process can sleep
3500 *
3501 * Returns 0 for success, >0 for handshake failure
3502 * <0 for fw upload failure.
3503 *
3504 * Remark: If bound IOC and a successful FWUpload was performed
3505 * on the bound IOC, the second image is discarded
3506 * and memory is free'd. Both channels must upload to prevent
3507 * IOC from running in degraded mode.
3508 */
3509static int
3510mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3511{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 u8 reply[sizeof(FWUploadReply_t)];
3513 FWUpload_t *prequest;
3514 FWUploadReply_t *preply;
3515 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 u32 flagsLength;
3517 int ii, sz, reply_sz;
3518 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303519 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 /* If the image size is 0, we are done.
3521 */
3522 if ((sz = ioc->facts.FWImageSize) == 0)
3523 return 0;
3524
Prakash, Sathya984621b2008-01-11 14:42:17 +05303525 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3526 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527
Eric Moore29dd3602007-09-14 18:46:51 -06003528 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3529 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003530
Eric Moorebc6e0892007-09-29 10:16:28 -06003531 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3532 kzalloc(ioc->req_sz, GFP_KERNEL);
3533 if (!prequest) {
3534 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3535 "while allocating memory \n", ioc->name));
3536 mpt_free_fw_memory(ioc);
3537 return -ENOMEM;
3538 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539
Eric Moorebc6e0892007-09-29 10:16:28 -06003540 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541
3542 reply_sz = sizeof(reply);
3543 memset(preply, 0, reply_sz);
3544
3545 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3546 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3547
3548 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3549 ptcsge->DetailsLength = 12;
3550 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3551 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003552 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303555 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3556 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3557 ioc->SGE_size;
3558 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3559 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3560 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003561 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303563 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3564 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565
Kashyap, Desai2f187862009-05-29 16:52:37 +05303566 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
3567 "rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568
3569 cmdStatus = -EFAULT;
3570 if (ii == 0) {
3571 /* Handshake transfer was complete and successful.
3572 * Check the Reply Frame.
3573 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303574 int status;
3575 status = le16_to_cpu(preply->IOCStatus) &
3576 MPI_IOCSTATUS_MASK;
3577 if (status == MPI_IOCSTATUS_SUCCESS &&
3578 ioc->facts.FWImageSize ==
3579 le32_to_cpu(preply->ActualImageSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 cmdStatus = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303582 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 ioc->name, cmdStatus));
3584
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003585
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586 if (cmdStatus) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303587 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
3588 "freeing image \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 mpt_free_fw_memory(ioc);
3590 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003591 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592
3593 return cmdStatus;
3594}
3595
3596/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003597/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 * mpt_downloadboot - DownloadBoot code
3599 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003600 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601 * @sleepFlag: Specifies whether the process can sleep
3602 *
3603 * FwDownloadBoot requires Programmed IO access.
3604 *
3605 * Returns 0 for success
3606 * -1 FW Image size is 0
3607 * -2 No valid cached_fw Pointer
3608 * <0 for fw upload failure.
3609 */
3610static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003611mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 MpiExtImageHeader_t *pExtImage;
3614 u32 fwSize;
3615 u32 diag0val;
3616 int count;
3617 u32 *ptrFw;
3618 u32 diagRwData;
3619 u32 nextImage;
3620 u32 load_addr;
3621 u32 ioc_state=0;
3622
Prakash, Sathya436ace72007-07-24 15:42:08 +05303623 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003624 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003625
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3627 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3628 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3629 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3630 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3631 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3632
3633 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3634
3635 /* wait 1 msec */
3636 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003637 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 } else {
3639 mdelay (1);
3640 }
3641
3642 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3643 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3644
3645 for (count = 0; count < 30; count ++) {
3646 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3647 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303648 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 ioc->name, count));
3650 break;
3651 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003652 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003654 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003656 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 }
3658 }
3659
3660 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303661 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003662 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 ioc->name, diag0val));
3664 return -3;
3665 }
3666
3667 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3668 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3669 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3670 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3671 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3672 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3673
3674 /* Set the DiagRwEn and Disable ARM bits */
3675 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3676
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 fwSize = (pFwHeader->ImageSize + 3)/4;
3678 ptrFw = (u32 *) pFwHeader;
3679
3680 /* Write the LoadStartAddress to the DiagRw Address Register
3681 * using Programmed IO
3682 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003683 if (ioc->errata_flag_1064)
3684 pci_enable_io_access(ioc->pcidev);
3685
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303687 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 ioc->name, pFwHeader->LoadStartAddress));
3689
Prakash, Sathya436ace72007-07-24 15:42:08 +05303690 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 ioc->name, fwSize*4, ptrFw));
3692 while (fwSize--) {
3693 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3694 }
3695
3696 nextImage = pFwHeader->NextImageHeaderOffset;
3697 while (nextImage) {
3698 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3699
3700 load_addr = pExtImage->LoadStartAddress;
3701
3702 fwSize = (pExtImage->ImageSize + 3) >> 2;
3703 ptrFw = (u32 *)pExtImage;
3704
Prakash, Sathya436ace72007-07-24 15:42:08 +05303705 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 +02003706 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3708
3709 while (fwSize--) {
3710 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3711 }
3712 nextImage = pExtImage->NextImageHeaderOffset;
3713 }
3714
3715 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303716 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3718
3719 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303720 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3722
3723 /* Clear the internal flash bad bit - autoincrementing register,
3724 * so must do two writes.
3725 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003726 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003727 /*
3728 * 1030 and 1035 H/W errata, workaround to access
3729 * the ClearFlashBadSignatureBit
3730 */
3731 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3732 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3733 diagRwData |= 0x40000000;
3734 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3735 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3736
3737 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3738 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3739 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3740 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3741
3742 /* wait 1 msec */
3743 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003744 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003745 } else {
3746 mdelay (1);
3747 }
3748 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003750 if (ioc->errata_flag_1064)
3751 pci_disable_io_access(ioc->pcidev);
3752
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303754 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003755 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003757 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303758 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759 ioc->name, diag0val));
3760 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3761
3762 /* Write 0xFF to reset the sequencer */
3763 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3764
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003765 if (ioc->bus_type == SAS) {
3766 ioc_state = mpt_GetIocState(ioc, 0);
3767 if ( (GetIocFacts(ioc, sleepFlag,
3768 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303769 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003770 ioc->name, ioc_state));
3771 return -EFAULT;
3772 }
3773 }
3774
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 for (count=0; count<HZ*20; count++) {
3776 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303777 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3778 "downloadboot successful! (count=%d) IocState=%x\n",
3779 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003780 if (ioc->bus_type == SAS) {
3781 return 0;
3782 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303784 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3785 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786 ioc->name));
3787 return -EFAULT;
3788 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303789 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3790 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 ioc->name));
3792 return 0;
3793 }
3794 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003795 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796 } else {
3797 mdelay (10);
3798 }
3799 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303800 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3801 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003802 return -EFAULT;
3803}
3804
3805/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003806/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003807 * KickStart - Perform hard reset of MPT adapter.
3808 * @ioc: Pointer to MPT_ADAPTER structure
3809 * @force: Force hard reset
3810 * @sleepFlag: Specifies whether the process can sleep
3811 *
3812 * This routine places MPT adapter in diagnostic mode via the
3813 * WriteSequence register, and then performs a hard reset of adapter
3814 * via the Diagnostic register.
3815 *
3816 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3817 * or NO_SLEEP (interrupt thread, use mdelay)
3818 * force - 1 if doorbell active, board fault state
3819 * board operational, IOC_RECOVERY or
3820 * IOC_BRINGUP and there is an alt_ioc.
3821 * 0 else
3822 *
3823 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003824 * 1 - hard reset, READY
3825 * 0 - no reset due to History bit, READY
3826 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827 * OR reset but failed to come READY
3828 * -2 - no reset, could not enter DIAG mode
3829 * -3 - reset but bad FW bit
3830 */
3831static int
3832KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3833{
3834 int hard_reset_done = 0;
3835 u32 ioc_state=0;
3836 int cnt,cntdn;
3837
Eric Moore29dd3602007-09-14 18:46:51 -06003838 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003839 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 /* Always issue a Msg Unit Reset first. This will clear some
3841 * SCSI bus hang conditions.
3842 */
3843 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3844
3845 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003846 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003847 } else {
3848 mdelay (1000);
3849 }
3850 }
3851
3852 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3853 if (hard_reset_done < 0)
3854 return hard_reset_done;
3855
Prakash, Sathya436ace72007-07-24 15:42:08 +05303856 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003857 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858
3859 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3860 for (cnt=0; cnt<cntdn; cnt++) {
3861 ioc_state = mpt_GetIocState(ioc, 1);
3862 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303863 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 ioc->name, cnt));
3865 return hard_reset_done;
3866 }
3867 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003868 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869 } else {
3870 mdelay (10);
3871 }
3872 }
3873
Eric Moore29dd3602007-09-14 18:46:51 -06003874 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3875 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876 return -1;
3877}
3878
3879/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003880/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 * mpt_diag_reset - Perform hard reset of the adapter.
3882 * @ioc: Pointer to MPT_ADAPTER structure
3883 * @ignore: Set if to honor and clear to ignore
3884 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003885 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 * else set to NO_SLEEP (use mdelay instead)
3887 *
3888 * This routine places the adapter in diagnostic mode via the
3889 * WriteSequence register and then performs a hard reset of adapter
3890 * via the Diagnostic register. Adapter should be in ready state
3891 * upon successful completion.
3892 *
3893 * Returns: 1 hard reset successful
3894 * 0 no reset performed because reset history bit set
3895 * -2 enabling diagnostic mode failed
3896 * -3 diagnostic reset failed
3897 */
3898static int
3899mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3900{
3901 u32 diag0val;
3902 u32 doorbell;
3903 int hard_reset_done = 0;
3904 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303906 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Kashyap, Desaid1306912009-08-05 12:53:51 +05303907 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908
Eric Moorecd2c6192007-01-29 09:47:47 -07003909 /* Clear any existing interrupts */
3910 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3911
Eric Moore87cf8982006-06-27 16:09:26 -06003912 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303913
3914 if (!ignore)
3915 return 0;
3916
Prakash, Sathya436ace72007-07-24 15:42:08 +05303917 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003918 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003919 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3920 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3921 if (sleepFlag == CAN_SLEEP)
3922 msleep(1);
3923 else
3924 mdelay(1);
3925
Kashyap, Desaid1306912009-08-05 12:53:51 +05303926 /*
3927 * Call each currently registered protocol IOC reset handler
3928 * with pre-reset indication.
3929 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3930 * MptResetHandlers[] registered yet.
3931 */
3932 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3933 if (MptResetHandlers[cb_idx])
3934 (*(MptResetHandlers[cb_idx]))(ioc,
3935 MPT_IOC_PRE_RESET);
3936 }
3937
Eric Moore87cf8982006-06-27 16:09:26 -06003938 for (count = 0; count < 60; count ++) {
3939 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3940 doorbell &= MPI_IOC_STATE_MASK;
3941
Prakash, Sathya436ace72007-07-24 15:42:08 +05303942 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003943 "looking for READY STATE: doorbell=%x"
3944 " count=%d\n",
3945 ioc->name, doorbell, count));
Kashyap, Desai2f187862009-05-29 16:52:37 +05303946
Eric Moore87cf8982006-06-27 16:09:26 -06003947 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003948 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003949 }
3950
3951 /* wait 1 sec */
3952 if (sleepFlag == CAN_SLEEP)
3953 msleep(1000);
3954 else
3955 mdelay(1000);
3956 }
3957 return -1;
3958 }
3959
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 /* Use "Diagnostic reset" method! (only thing available!) */
3961 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3962
Prakash, Sathya436ace72007-07-24 15:42:08 +05303963 if (ioc->debug_level & MPT_DEBUG) {
3964 if (ioc->alt_ioc)
3965 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3966 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303968 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969
3970 /* Do the reset if we are told to ignore the reset history
3971 * or if the reset history is 0
3972 */
3973 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3974 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3975 /* Write magic sequence to WriteSequence register
3976 * Loop until in diagnostic mode
3977 */
3978 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3979 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3980 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3981 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3982 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3983 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3984
3985 /* wait 100 msec */
3986 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003987 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988 } else {
3989 mdelay (100);
3990 }
3991
3992 count++;
3993 if (count > 20) {
3994 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3995 ioc->name, diag0val);
3996 return -2;
3997
3998 }
3999
4000 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4001
Prakash, Sathya436ace72007-07-24 15:42:08 +05304002 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003 ioc->name, diag0val));
4004 }
4005
Prakash, Sathya436ace72007-07-24 15:42:08 +05304006 if (ioc->debug_level & MPT_DEBUG) {
4007 if (ioc->alt_ioc)
4008 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4009 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304011 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 /*
4013 * Disable the ARM (Bug fix)
4014 *
4015 */
4016 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004017 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018
4019 /*
4020 * Now hit the reset bit in the Diagnostic register
4021 * (THE BIG HAMMER!) (Clears DRWE bit).
4022 */
4023 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
4024 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304025 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 ioc->name));
4027
4028 /*
4029 * Call each currently registered protocol IOC reset handler
4030 * with pre-reset indication.
4031 * NOTE: If we're doing _IOC_BRINGUP, there can be no
4032 * MptResetHandlers[] registered yet.
4033 */
Kashyap, Desaid1306912009-08-05 12:53:51 +05304034 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
4035 if (MptResetHandlers[cb_idx]) {
4036 mpt_signal_reset(cb_idx,
4037 ioc, MPT_IOC_PRE_RESET);
4038 if (ioc->alt_ioc) {
4039 mpt_signal_reset(cb_idx,
4040 ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 }
4042 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 }
4044
Eric Moore0ccdb002006-07-11 17:33:13 -06004045 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304046 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06004047 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304048 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4049 else
4050 cached_fw = NULL;
4051 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052 /* If the DownloadBoot operation fails, the
4053 * IOC will be left unusable. This is a fatal error
4054 * case. _diag_reset will return < 0
4055 */
4056 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304057 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4059 break;
4060 }
4061
Prakash, Sathya436ace72007-07-24 15:42:08 +05304062 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304063 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004064 /* wait 1 sec */
4065 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004066 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067 } else {
4068 mdelay (1000);
4069 }
4070 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304071 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004072 printk(MYIOC_s_WARN_FMT
4073 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074 }
4075
4076 } else {
4077 /* Wait for FW to reload and for board
4078 * to go to the READY state.
4079 * Maximum wait is 60 seconds.
4080 * If fail, no error will check again
4081 * with calling program.
4082 */
4083 for (count = 0; count < 60; count ++) {
4084 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4085 doorbell &= MPI_IOC_STATE_MASK;
4086
Kashyap, Desai2f187862009-05-29 16:52:37 +05304087 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4088 "looking for READY STATE: doorbell=%x"
4089 " count=%d\n", ioc->name, doorbell, count));
4090
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091 if (doorbell == MPI_IOC_STATE_READY) {
4092 break;
4093 }
4094
4095 /* wait 1 sec */
4096 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004097 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098 } else {
4099 mdelay (1000);
4100 }
4101 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05304102
4103 if (doorbell != MPI_IOC_STATE_READY)
4104 printk(MYIOC_s_ERR_FMT "Failed to come READY "
4105 "after reset! IocState=%x", ioc->name,
4106 doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004107 }
4108 }
4109
4110 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304111 if (ioc->debug_level & MPT_DEBUG) {
4112 if (ioc->alt_ioc)
4113 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4114 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4115 ioc->name, diag0val, diag1val));
4116 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117
4118 /* Clear RESET_HISTORY bit! Place board in the
4119 * diagnostic mode to update the diag register.
4120 */
4121 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4122 count = 0;
4123 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4124 /* Write magic sequence to WriteSequence register
4125 * Loop until in diagnostic mode
4126 */
4127 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4128 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4129 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4130 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4131 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4132 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4133
4134 /* wait 100 msec */
4135 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004136 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137 } else {
4138 mdelay (100);
4139 }
4140
4141 count++;
4142 if (count > 20) {
4143 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4144 ioc->name, diag0val);
4145 break;
4146 }
4147 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4148 }
4149 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4150 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4151 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4152 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4153 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4154 ioc->name);
4155 }
4156
4157 /* Disable Diagnostic Mode
4158 */
4159 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4160
4161 /* Check FW reload status flags.
4162 */
4163 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4164 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4165 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4166 ioc->name, diag0val);
4167 return -3;
4168 }
4169
Prakash, Sathya436ace72007-07-24 15:42:08 +05304170 if (ioc->debug_level & MPT_DEBUG) {
4171 if (ioc->alt_ioc)
4172 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4173 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304175 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176
4177 /*
4178 * Reset flag that says we've enabled event notification
4179 */
4180 ioc->facts.EventState = 0;
4181
4182 if (ioc->alt_ioc)
4183 ioc->alt_ioc->facts.EventState = 0;
4184
4185 return hard_reset_done;
4186}
4187
4188/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004189/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 * SendIocReset - Send IOCReset request to MPT adapter.
4191 * @ioc: Pointer to MPT_ADAPTER structure
4192 * @reset_type: reset type, expected values are
4193 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004194 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195 *
4196 * Send IOCReset request to the MPT adapter.
4197 *
4198 * Returns 0 for success, non-zero for failure.
4199 */
4200static int
4201SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4202{
4203 int r;
4204 u32 state;
4205 int cntdn, count;
4206
Prakash, Sathya436ace72007-07-24 15:42:08 +05304207 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208 ioc->name, reset_type));
4209 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4210 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4211 return r;
4212
4213 /* FW ACK'd request, wait for READY state
4214 */
4215 count = 0;
4216 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4217
4218 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4219 cntdn--;
4220 count++;
4221 if (!cntdn) {
4222 if (sleepFlag != CAN_SLEEP)
4223 count *= 10;
4224
Kashyap, Desai2f187862009-05-29 16:52:37 +05304225 printk(MYIOC_s_ERR_FMT
4226 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
4227 ioc->name, state, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 return -ETIME;
4229 }
4230
4231 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004232 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 } else {
4234 mdelay (1); /* 1 msec delay */
4235 }
4236 }
4237
4238 /* TODO!
4239 * Cleanup all event stuff for this IOC; re-issue EventNotification
4240 * request if needed.
4241 */
4242 if (ioc->facts.Function)
4243 ioc->facts.EventState = 0;
4244
4245 return 0;
4246}
4247
4248/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004249/**
4250 * initChainBuffers - Allocate memory for and initialize chain buffers
4251 * @ioc: Pointer to MPT_ADAPTER structure
4252 *
4253 * Allocates memory for and initializes chain buffers,
4254 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255 */
4256static int
4257initChainBuffers(MPT_ADAPTER *ioc)
4258{
4259 u8 *mem;
4260 int sz, ii, num_chain;
4261 int scale, num_sge, numSGE;
4262
4263 /* ReqToChain size must equal the req_depth
4264 * index = req_idx
4265 */
4266 if (ioc->ReqToChain == NULL) {
4267 sz = ioc->req_depth * sizeof(int);
4268 mem = kmalloc(sz, GFP_ATOMIC);
4269 if (mem == NULL)
4270 return -1;
4271
4272 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304273 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274 ioc->name, mem, sz));
4275 mem = kmalloc(sz, GFP_ATOMIC);
4276 if (mem == NULL)
4277 return -1;
4278
4279 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304280 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 ioc->name, mem, sz));
4282 }
4283 for (ii = 0; ii < ioc->req_depth; ii++) {
4284 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4285 }
4286
4287 /* ChainToChain size must equal the total number
4288 * of chain buffers to be allocated.
4289 * index = chain_idx
4290 *
4291 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004292 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293 *
4294 * num_sge = num sge in request frame + last chain buffer
4295 * scale = num sge per chain buffer if no chain element
4296 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304297 scale = ioc->req_sz / ioc->SGE_size;
4298 if (ioc->sg_addr_size == sizeof(u64))
4299 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304301 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304303 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304305 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304307 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4308 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304310 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 ioc->name, num_sge, numSGE));
4312
Kashyap, Desai2f187862009-05-29 16:52:37 +05304313 if (ioc->bus_type == FC) {
4314 if (numSGE > MPT_SCSI_FC_SG_DEPTH)
4315 numSGE = MPT_SCSI_FC_SG_DEPTH;
4316 } else {
4317 if (numSGE > MPT_SCSI_SG_DEPTH)
4318 numSGE = MPT_SCSI_SG_DEPTH;
4319 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320
4321 num_chain = 1;
4322 while (numSGE - num_sge > 0) {
4323 num_chain++;
4324 num_sge += (scale - 1);
4325 }
4326 num_chain++;
4327
Prakash, Sathya436ace72007-07-24 15:42:08 +05304328 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329 ioc->name, numSGE, num_sge, num_chain));
4330
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004331 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 num_chain *= MPT_SCSI_CAN_QUEUE;
4333 else
4334 num_chain *= MPT_FC_CAN_QUEUE;
4335
4336 ioc->num_chain = num_chain;
4337
4338 sz = num_chain * sizeof(int);
4339 if (ioc->ChainToChain == NULL) {
4340 mem = kmalloc(sz, GFP_ATOMIC);
4341 if (mem == NULL)
4342 return -1;
4343
4344 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304345 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 ioc->name, mem, sz));
4347 } else {
4348 mem = (u8 *) ioc->ChainToChain;
4349 }
4350 memset(mem, 0xFF, sz);
4351 return num_chain;
4352}
4353
4354/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004355/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4357 * @ioc: Pointer to MPT_ADAPTER structure
4358 *
4359 * This routine allocates memory for the MPT reply and request frame
4360 * pools (if necessary), and primes the IOC reply FIFO with
4361 * reply frames.
4362 *
4363 * Returns 0 for success, non-zero for failure.
4364 */
4365static int
4366PrimeIocFifos(MPT_ADAPTER *ioc)
4367{
4368 MPT_FRAME_HDR *mf;
4369 unsigned long flags;
4370 dma_addr_t alloc_dma;
4371 u8 *mem;
4372 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304373 u64 dma_mask;
4374
4375 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376
4377 /* Prime reply FIFO... */
4378
4379 if (ioc->reply_frames == NULL) {
4380 if ( (num_chain = initChainBuffers(ioc)) < 0)
4381 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304382 /*
4383 * 1078 errata workaround for the 36GB limitation
4384 */
4385 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
Andrew Morton8e20ce92009-06-18 16:49:17 -07004386 ioc->dma_mask > DMA_BIT_MASK(35)) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304387 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4388 && !pci_set_consistent_dma_mask(ioc->pcidev,
4389 DMA_BIT_MASK(32))) {
Andrew Morton8e20ce92009-06-18 16:49:17 -07004390 dma_mask = DMA_BIT_MASK(35);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304391 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4392 "setting 35 bit addressing for "
4393 "Request/Reply/Chain and Sense Buffers\n",
4394 ioc->name));
4395 } else {
4396 /*Reseting DMA mask to 64 bit*/
4397 pci_set_dma_mask(ioc->pcidev,
4398 DMA_BIT_MASK(64));
4399 pci_set_consistent_dma_mask(ioc->pcidev,
4400 DMA_BIT_MASK(64));
4401
4402 printk(MYIOC_s_ERR_FMT
4403 "failed setting 35 bit addressing for "
4404 "Request/Reply/Chain and Sense Buffers\n",
4405 ioc->name);
4406 return -1;
4407 }
4408 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409
4410 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304411 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304413 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 ioc->name, reply_sz, reply_sz));
4415
4416 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304417 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304419 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 ioc->name, sz, sz));
4421 total_size += sz;
4422
4423 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304424 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304426 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 ioc->name, sz, sz, num_chain));
4428
4429 total_size += sz;
4430 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4431 if (mem == NULL) {
4432 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4433 ioc->name);
4434 goto out_fail;
4435 }
4436
Prakash, Sathya436ace72007-07-24 15:42:08 +05304437 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4439
4440 memset(mem, 0, total_size);
4441 ioc->alloc_total += total_size;
4442 ioc->alloc = mem;
4443 ioc->alloc_dma = alloc_dma;
4444 ioc->alloc_sz = total_size;
4445 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4446 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4447
Prakash, Sathya436ace72007-07-24 15:42:08 +05304448 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004449 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4450
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 alloc_dma += reply_sz;
4452 mem += reply_sz;
4453
4454 /* Request FIFO - WE manage this! */
4455
4456 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4457 ioc->req_frames_dma = alloc_dma;
4458
Prakash, Sathya436ace72007-07-24 15:42:08 +05304459 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 ioc->name, mem, (void *)(ulong)alloc_dma));
4461
4462 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4463
4464#if defined(CONFIG_MTRR) && 0
4465 /*
4466 * Enable Write Combining MTRR for IOC's memory region.
4467 * (at least as much as we can; "size and base must be
4468 * multiples of 4 kiB"
4469 */
4470 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4471 sz,
4472 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304473 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 ioc->name, ioc->req_frames_dma, sz));
4475#endif
4476
4477 for (i = 0; i < ioc->req_depth; i++) {
4478 alloc_dma += ioc->req_sz;
4479 mem += ioc->req_sz;
4480 }
4481
4482 ioc->ChainBuffer = mem;
4483 ioc->ChainBufferDMA = alloc_dma;
4484
Prakash, Sathya436ace72007-07-24 15:42:08 +05304485 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4487
4488 /* Initialize the free chain Q.
4489 */
4490
4491 INIT_LIST_HEAD(&ioc->FreeChainQ);
4492
4493 /* Post the chain buffers to the FreeChainQ.
4494 */
4495 mem = (u8 *)ioc->ChainBuffer;
4496 for (i=0; i < num_chain; i++) {
4497 mf = (MPT_FRAME_HDR *) mem;
4498 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4499 mem += ioc->req_sz;
4500 }
4501
4502 /* Initialize Request frames linked list
4503 */
4504 alloc_dma = ioc->req_frames_dma;
4505 mem = (u8 *) ioc->req_frames;
4506
4507 spin_lock_irqsave(&ioc->FreeQlock, flags);
4508 INIT_LIST_HEAD(&ioc->FreeQ);
4509 for (i = 0; i < ioc->req_depth; i++) {
4510 mf = (MPT_FRAME_HDR *) mem;
4511
4512 /* Queue REQUESTs *internally*! */
4513 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4514
4515 mem += ioc->req_sz;
4516 }
4517 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4518
4519 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4520 ioc->sense_buf_pool =
4521 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4522 if (ioc->sense_buf_pool == NULL) {
4523 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4524 ioc->name);
4525 goto out_fail;
4526 }
4527
4528 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4529 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304530 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4532
4533 }
4534
4535 /* Post Reply frames to FIFO
4536 */
4537 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304538 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4540
4541 for (i = 0; i < ioc->reply_depth; i++) {
4542 /* Write each address to the IOC! */
4543 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4544 alloc_dma += ioc->reply_sz;
4545 }
4546
Andrew Morton8e20ce92009-06-18 16:49:17 -07004547 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304548 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4549 ioc->dma_mask))
4550 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4551 "restoring 64 bit addressing\n", ioc->name));
4552
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553 return 0;
4554
4555out_fail:
Kashyap, Desai2f187862009-05-29 16:52:37 +05304556
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557 if (ioc->alloc != NULL) {
4558 sz = ioc->alloc_sz;
4559 pci_free_consistent(ioc->pcidev,
4560 sz,
4561 ioc->alloc, ioc->alloc_dma);
4562 ioc->reply_frames = NULL;
4563 ioc->req_frames = NULL;
4564 ioc->alloc_total -= sz;
4565 }
4566 if (ioc->sense_buf_pool != NULL) {
4567 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4568 pci_free_consistent(ioc->pcidev,
4569 sz,
4570 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4571 ioc->sense_buf_pool = NULL;
4572 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304573
Andrew Morton8e20ce92009-06-18 16:49:17 -07004574 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304575 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4576 DMA_BIT_MASK(64)))
4577 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4578 "restoring 64 bit addressing\n", ioc->name));
4579
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580 return -1;
4581}
4582
4583/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4584/**
4585 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4586 * from IOC via doorbell handshake method.
4587 * @ioc: Pointer to MPT_ADAPTER structure
4588 * @reqBytes: Size of the request in bytes
4589 * @req: Pointer to MPT request frame
4590 * @replyBytes: Expected size of the reply in bytes
4591 * @u16reply: Pointer to area where reply should be written
4592 * @maxwait: Max wait time for a reply (in seconds)
4593 * @sleepFlag: Specifies whether the process can sleep
4594 *
4595 * NOTES: It is the callers responsibility to byte-swap fields in the
4596 * request which are greater than 1 byte in size. It is also the
4597 * callers responsibility to byte-swap response fields which are
4598 * greater than 1 byte in size.
4599 *
4600 * Returns 0 for success, non-zero for failure.
4601 */
4602static int
4603mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004604 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605{
4606 MPIDefaultReply_t *mptReply;
4607 int failcnt = 0;
4608 int t;
4609
4610 /*
4611 * Get ready to cache a handshake reply
4612 */
4613 ioc->hs_reply_idx = 0;
4614 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4615 mptReply->MsgLength = 0;
4616
4617 /*
4618 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4619 * then tell IOC that we want to handshake a request of N words.
4620 * (WRITE u32val to Doorbell reg).
4621 */
4622 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4623 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4624 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4625 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4626
4627 /*
4628 * Wait for IOC's doorbell handshake int
4629 */
4630 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4631 failcnt++;
4632
Prakash, Sathya436ace72007-07-24 15:42:08 +05304633 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4635
4636 /* Read doorbell and check for active bit */
4637 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4638 return -1;
4639
4640 /*
4641 * Clear doorbell int (WRITE 0 to IntStatus reg),
4642 * then wait for IOC to ACKnowledge that it's ready for
4643 * our handshake request.
4644 */
4645 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4646 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4647 failcnt++;
4648
4649 if (!failcnt) {
4650 int ii;
4651 u8 *req_as_bytes = (u8 *) req;
4652
4653 /*
4654 * Stuff request words via doorbell handshake,
4655 * with ACK from IOC for each.
4656 */
4657 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4658 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4659 (req_as_bytes[(ii*4) + 1] << 8) |
4660 (req_as_bytes[(ii*4) + 2] << 16) |
4661 (req_as_bytes[(ii*4) + 3] << 24));
4662
4663 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4664 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4665 failcnt++;
4666 }
4667
Prakash, Sathya436ace72007-07-24 15:42:08 +05304668 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004669 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670
Prakash, Sathya436ace72007-07-24 15:42:08 +05304671 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4673
4674 /*
4675 * Wait for completion of doorbell handshake reply from the IOC
4676 */
4677 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4678 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004679
Prakash, Sathya436ace72007-07-24 15:42:08 +05304680 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4682
4683 /*
4684 * Copy out the cached reply...
4685 */
4686 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4687 u16reply[ii] = ioc->hs_reply[ii];
4688 } else {
4689 return -99;
4690 }
4691
4692 return -failcnt;
4693}
4694
4695/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004696/**
4697 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698 * @ioc: Pointer to MPT_ADAPTER structure
4699 * @howlong: How long to wait (in seconds)
4700 * @sleepFlag: Specifies whether the process can sleep
4701 *
4702 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004703 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4704 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705 *
4706 * Returns a negative value on failure, else wait loop count.
4707 */
4708static int
4709WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4710{
4711 int cntdn;
4712 int count = 0;
4713 u32 intstat=0;
4714
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004715 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716
4717 if (sleepFlag == CAN_SLEEP) {
4718 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004719 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4721 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4722 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723 count++;
4724 }
4725 } else {
4726 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004727 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4729 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4730 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731 count++;
4732 }
4733 }
4734
4735 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304736 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737 ioc->name, count));
4738 return count;
4739 }
4740
4741 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4742 ioc->name, count, intstat);
4743 return -1;
4744}
4745
4746/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004747/**
4748 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004749 * @ioc: Pointer to MPT_ADAPTER structure
4750 * @howlong: How long to wait (in seconds)
4751 * @sleepFlag: Specifies whether the process can sleep
4752 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004753 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4754 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 *
4756 * Returns a negative value on failure, else wait loop count.
4757 */
4758static int
4759WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4760{
4761 int cntdn;
4762 int count = 0;
4763 u32 intstat=0;
4764
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004765 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 if (sleepFlag == CAN_SLEEP) {
4767 while (--cntdn) {
4768 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4769 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4770 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004771 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772 count++;
4773 }
4774 } else {
4775 while (--cntdn) {
4776 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4777 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4778 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004779 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780 count++;
4781 }
4782 }
4783
4784 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304785 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786 ioc->name, count, howlong));
4787 return count;
4788 }
4789
4790 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4791 ioc->name, count, intstat);
4792 return -1;
4793}
4794
4795/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004796/**
4797 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798 * @ioc: Pointer to MPT_ADAPTER structure
4799 * @howlong: How long to wait (in seconds)
4800 * @sleepFlag: Specifies whether the process can sleep
4801 *
4802 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4803 * Reply is cached to IOC private area large enough to hold a maximum
4804 * of 128 bytes of reply data.
4805 *
4806 * Returns a negative value on failure, else size of reply in WORDS.
4807 */
4808static int
4809WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4810{
4811 int u16cnt = 0;
4812 int failcnt = 0;
4813 int t;
4814 u16 *hs_reply = ioc->hs_reply;
4815 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4816 u16 hword;
4817
4818 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4819
4820 /*
4821 * Get first two u16's so we can look at IOC's intended reply MsgLength
4822 */
4823 u16cnt=0;
4824 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4825 failcnt++;
4826 } else {
4827 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4828 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4829 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4830 failcnt++;
4831 else {
4832 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4833 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4834 }
4835 }
4836
Prakash, Sathya436ace72007-07-24 15:42:08 +05304837 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004838 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4840
4841 /*
4842 * If no error (and IOC said MsgLength is > 0), piece together
4843 * reply 16 bits at a time.
4844 */
4845 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4846 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4847 failcnt++;
4848 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4849 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004850 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851 hs_reply[u16cnt] = hword;
4852 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4853 }
4854
4855 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4856 failcnt++;
4857 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4858
4859 if (failcnt) {
4860 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4861 ioc->name);
4862 return -failcnt;
4863 }
4864#if 0
4865 else if (u16cnt != (2 * mptReply->MsgLength)) {
4866 return -101;
4867 }
4868 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4869 return -102;
4870 }
4871#endif
4872
Prakash, Sathya436ace72007-07-24 15:42:08 +05304873 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004874 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875
Prakash, Sathya436ace72007-07-24 15:42:08 +05304876 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004877 ioc->name, t, u16cnt/2));
4878 return u16cnt/2;
4879}
4880
4881/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004882/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 * GetLanConfigPages - Fetch LANConfig pages.
4884 * @ioc: Pointer to MPT_ADAPTER structure
4885 *
4886 * Return: 0 for success
4887 * -ENOMEM if no memory available
4888 * -EPERM if not allowed due to ISR context
4889 * -EAGAIN if no msg frames currently available
4890 * -EFAULT for non-successful reply or no reply (timeout)
4891 */
4892static int
4893GetLanConfigPages(MPT_ADAPTER *ioc)
4894{
4895 ConfigPageHeader_t hdr;
4896 CONFIGPARMS cfg;
4897 LANPage0_t *ppage0_alloc;
4898 dma_addr_t page0_dma;
4899 LANPage1_t *ppage1_alloc;
4900 dma_addr_t page1_dma;
4901 int rc = 0;
4902 int data_sz;
4903 int copy_sz;
4904
4905 /* Get LAN Page 0 header */
4906 hdr.PageVersion = 0;
4907 hdr.PageLength = 0;
4908 hdr.PageNumber = 0;
4909 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004910 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004911 cfg.physAddr = -1;
4912 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4913 cfg.dir = 0;
4914 cfg.pageAddr = 0;
4915 cfg.timeout = 0;
4916
4917 if ((rc = mpt_config(ioc, &cfg)) != 0)
4918 return rc;
4919
4920 if (hdr.PageLength > 0) {
4921 data_sz = hdr.PageLength * 4;
4922 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4923 rc = -ENOMEM;
4924 if (ppage0_alloc) {
4925 memset((u8 *)ppage0_alloc, 0, data_sz);
4926 cfg.physAddr = page0_dma;
4927 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4928
4929 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4930 /* save the data */
4931 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4932 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4933
4934 }
4935
4936 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4937
4938 /* FIXME!
4939 * Normalize endianness of structure data,
4940 * by byte-swapping all > 1 byte fields!
4941 */
4942
4943 }
4944
4945 if (rc)
4946 return rc;
4947 }
4948
4949 /* Get LAN Page 1 header */
4950 hdr.PageVersion = 0;
4951 hdr.PageLength = 0;
4952 hdr.PageNumber = 1;
4953 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004954 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955 cfg.physAddr = -1;
4956 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4957 cfg.dir = 0;
4958 cfg.pageAddr = 0;
4959
4960 if ((rc = mpt_config(ioc, &cfg)) != 0)
4961 return rc;
4962
4963 if (hdr.PageLength == 0)
4964 return 0;
4965
4966 data_sz = hdr.PageLength * 4;
4967 rc = -ENOMEM;
4968 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4969 if (ppage1_alloc) {
4970 memset((u8 *)ppage1_alloc, 0, data_sz);
4971 cfg.physAddr = page1_dma;
4972 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4973
4974 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4975 /* save the data */
4976 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4977 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4978 }
4979
4980 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4981
4982 /* FIXME!
4983 * Normalize endianness of structure data,
4984 * by byte-swapping all > 1 byte fields!
4985 */
4986
4987 }
4988
4989 return rc;
4990}
4991
4992/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004993/**
4994 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004995 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004996 * @persist_opcode: see below
4997 *
4998 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4999 * devices not currently present.
5000 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
5001 *
5002 * NOTE: Don't use not this function during interrupt time.
5003 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005004 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005005 */
5006
5007/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5008int
5009mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
5010{
5011 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
5012 SasIoUnitControlReply_t *sasIoUnitCntrReply;
5013 MPT_FRAME_HDR *mf = NULL;
5014 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305015 int ret = 0;
5016 unsigned long timeleft;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005017
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305018 mutex_lock(&ioc->mptbase_cmds.mutex);
5019
5020 /* init the internal cmd struct */
5021 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
5022 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005023
5024 /* insure garbage is not sent to fw */
5025 switch(persist_opcode) {
5026
5027 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
5028 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
5029 break;
5030
5031 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305032 ret = -1;
5033 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005034 }
5035
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305036 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
5037 __func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005038
5039 /* Get a MF for this command.
5040 */
5041 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305042 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
5043 ret = -1;
5044 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005045 }
5046
5047 mpi_hdr = (MPIHeader_t *) mf;
5048 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
5049 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
5050 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
5051 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
5052 sasIoUnitCntrReq->Operation = persist_opcode;
5053
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005054 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305055 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
5056 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
5057 ret = -ETIME;
5058 printk(KERN_DEBUG "%s: failed\n", __func__);
5059 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
5060 goto out;
5061 if (!timeleft) {
5062 printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n",
5063 ioc->name, __func__);
5064 mpt_HardResetHandler(ioc, CAN_SLEEP);
5065 mpt_free_msg_frame(ioc, mf);
5066 }
5067 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005068 }
5069
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305070 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
5071 ret = -1;
5072 goto out;
5073 }
5074
5075 sasIoUnitCntrReply =
5076 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5077 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5078 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5079 __func__, sasIoUnitCntrReply->IOCStatus,
5080 sasIoUnitCntrReply->IOCLogInfo);
5081 printk(KERN_DEBUG "%s: failed\n", __func__);
5082 ret = -1;
5083 } else
5084 printk(KERN_DEBUG "%s: success\n", __func__);
5085 out:
5086
5087 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5088 mutex_unlock(&ioc->mptbase_cmds.mutex);
5089 return ret;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005090}
5091
5092/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005093
5094static void
5095mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5096 MpiEventDataRaid_t * pRaidEventData)
5097{
5098 int volume;
5099 int reason;
5100 int disk;
5101 int status;
5102 int flags;
5103 int state;
5104
5105 volume = pRaidEventData->VolumeID;
5106 reason = pRaidEventData->ReasonCode;
5107 disk = pRaidEventData->PhysDiskNum;
5108 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5109 flags = (status >> 0) & 0xff;
5110 state = (status >> 8) & 0xff;
5111
5112 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5113 return;
5114 }
5115
5116 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5117 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5118 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005119 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5120 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005121 } else {
5122 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5123 ioc->name, volume);
5124 }
5125
5126 switch(reason) {
5127 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5128 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5129 ioc->name);
5130 break;
5131
5132 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5133
5134 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5135 ioc->name);
5136 break;
5137
5138 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5139 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5140 ioc->name);
5141 break;
5142
5143 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5144 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5145 ioc->name,
5146 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5147 ? "optimal"
5148 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5149 ? "degraded"
5150 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5151 ? "failed"
5152 : "state unknown",
5153 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5154 ? ", enabled" : "",
5155 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5156 ? ", quiesced" : "",
5157 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5158 ? ", resync in progress" : "" );
5159 break;
5160
5161 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5162 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5163 ioc->name, disk);
5164 break;
5165
5166 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5167 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5168 ioc->name);
5169 break;
5170
5171 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5172 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5173 ioc->name);
5174 break;
5175
5176 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5177 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5178 ioc->name);
5179 break;
5180
5181 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5182 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5183 ioc->name,
5184 state == MPI_PHYSDISK0_STATUS_ONLINE
5185 ? "online"
5186 : state == MPI_PHYSDISK0_STATUS_MISSING
5187 ? "missing"
5188 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5189 ? "not compatible"
5190 : state == MPI_PHYSDISK0_STATUS_FAILED
5191 ? "failed"
5192 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5193 ? "initializing"
5194 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5195 ? "offline requested"
5196 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5197 ? "failed requested"
5198 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5199 ? "offline"
5200 : "state unknown",
5201 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5202 ? ", out of sync" : "",
5203 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5204 ? ", quiesced" : "" );
5205 break;
5206
5207 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5208 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5209 ioc->name, disk);
5210 break;
5211
5212 case MPI_EVENT_RAID_RC_SMART_DATA:
5213 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5214 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5215 break;
5216
5217 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5218 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5219 ioc->name, disk);
5220 break;
5221 }
5222}
5223
5224/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005225/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5227 * @ioc: Pointer to MPT_ADAPTER structure
5228 *
5229 * Returns: 0 for success
5230 * -ENOMEM if no memory available
5231 * -EPERM if not allowed due to ISR context
5232 * -EAGAIN if no msg frames currently available
5233 * -EFAULT for non-successful reply or no reply (timeout)
5234 */
5235static int
5236GetIoUnitPage2(MPT_ADAPTER *ioc)
5237{
5238 ConfigPageHeader_t hdr;
5239 CONFIGPARMS cfg;
5240 IOUnitPage2_t *ppage_alloc;
5241 dma_addr_t page_dma;
5242 int data_sz;
5243 int rc;
5244
5245 /* Get the page header */
5246 hdr.PageVersion = 0;
5247 hdr.PageLength = 0;
5248 hdr.PageNumber = 2;
5249 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005250 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251 cfg.physAddr = -1;
5252 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5253 cfg.dir = 0;
5254 cfg.pageAddr = 0;
5255 cfg.timeout = 0;
5256
5257 if ((rc = mpt_config(ioc, &cfg)) != 0)
5258 return rc;
5259
5260 if (hdr.PageLength == 0)
5261 return 0;
5262
5263 /* Read the config page */
5264 data_sz = hdr.PageLength * 4;
5265 rc = -ENOMEM;
5266 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5267 if (ppage_alloc) {
5268 memset((u8 *)ppage_alloc, 0, data_sz);
5269 cfg.physAddr = page_dma;
5270 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5271
5272 /* If Good, save data */
5273 if ((rc = mpt_config(ioc, &cfg)) == 0)
5274 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5275
5276 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5277 }
5278
5279 return rc;
5280}
5281
5282/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005283/**
5284 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005285 * @ioc: Pointer to a Adapter Strucutre
5286 * @portnum: IOC port number
5287 *
5288 * Return: -EFAULT if read of config page header fails
5289 * or if no nvram
5290 * If read of SCSI Port Page 0 fails,
5291 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5292 * Adapter settings: async, narrow
5293 * Return 1
5294 * If read of SCSI Port Page 2 fails,
5295 * Adapter settings valid
5296 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5297 * Return 1
5298 * Else
5299 * Both valid
5300 * Return 0
5301 * CHECK - what type of locking mechanisms should be used????
5302 */
5303static int
5304mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5305{
5306 u8 *pbuf;
5307 dma_addr_t buf_dma;
5308 CONFIGPARMS cfg;
5309 ConfigPageHeader_t header;
5310 int ii;
5311 int data, rc = 0;
5312
5313 /* Allocate memory
5314 */
5315 if (!ioc->spi_data.nvram) {
5316 int sz;
5317 u8 *mem;
5318 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5319 mem = kmalloc(sz, GFP_ATOMIC);
5320 if (mem == NULL)
5321 return -EFAULT;
5322
5323 ioc->spi_data.nvram = (int *) mem;
5324
Prakash, Sathya436ace72007-07-24 15:42:08 +05305325 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005326 ioc->name, ioc->spi_data.nvram, sz));
5327 }
5328
5329 /* Invalidate NVRAM information
5330 */
5331 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5332 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5333 }
5334
5335 /* Read SPP0 header, allocate memory, then read page.
5336 */
5337 header.PageVersion = 0;
5338 header.PageLength = 0;
5339 header.PageNumber = 0;
5340 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005341 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342 cfg.physAddr = -1;
5343 cfg.pageAddr = portnum;
5344 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5345 cfg.dir = 0;
5346 cfg.timeout = 0; /* use default */
5347 if (mpt_config(ioc, &cfg) != 0)
5348 return -EFAULT;
5349
5350 if (header.PageLength > 0) {
5351 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5352 if (pbuf) {
5353 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5354 cfg.physAddr = buf_dma;
5355 if (mpt_config(ioc, &cfg) != 0) {
5356 ioc->spi_data.maxBusWidth = MPT_NARROW;
5357 ioc->spi_data.maxSyncOffset = 0;
5358 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5359 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5360 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305361 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5362 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005363 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005364 } else {
5365 /* Save the Port Page 0 data
5366 */
5367 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5368 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5369 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5370
5371 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5372 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005373 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5374 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375 ioc->name, pPP0->Capabilities));
5376 }
5377 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5378 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5379 if (data) {
5380 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5381 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5382 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305383 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5384 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005385 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 } else {
5387 ioc->spi_data.maxSyncOffset = 0;
5388 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5389 }
5390
5391 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5392
5393 /* Update the minSyncFactor based on bus type.
5394 */
5395 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5396 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5397
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005398 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305400 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5401 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005402 ioc->name, ioc->spi_data.minSyncFactor));
5403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 }
5405 }
5406 if (pbuf) {
5407 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5408 }
5409 }
5410 }
5411
5412 /* SCSI Port Page 2 - Read the header then the page.
5413 */
5414 header.PageVersion = 0;
5415 header.PageLength = 0;
5416 header.PageNumber = 2;
5417 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005418 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419 cfg.physAddr = -1;
5420 cfg.pageAddr = portnum;
5421 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5422 cfg.dir = 0;
5423 if (mpt_config(ioc, &cfg) != 0)
5424 return -EFAULT;
5425
5426 if (header.PageLength > 0) {
5427 /* Allocate memory and read SCSI Port Page 2
5428 */
5429 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5430 if (pbuf) {
5431 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5432 cfg.physAddr = buf_dma;
5433 if (mpt_config(ioc, &cfg) != 0) {
5434 /* Nvram data is left with INVALID mark
5435 */
5436 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005437 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5438
5439 /* This is an ATTO adapter, read Page2 accordingly
5440 */
5441 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5442 ATTODeviceInfo_t *pdevice = NULL;
5443 u16 ATTOFlags;
5444
5445 /* Save the Port Page 2 data
5446 * (reformat into a 32bit quantity)
5447 */
5448 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5449 pdevice = &pPP2->DeviceSettings[ii];
5450 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5451 data = 0;
5452
5453 /* Translate ATTO device flags to LSI format
5454 */
5455 if (ATTOFlags & ATTOFLAG_DISC)
5456 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5457 if (ATTOFlags & ATTOFLAG_ID_ENB)
5458 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5459 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5460 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5461 if (ATTOFlags & ATTOFLAG_TAGGED)
5462 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5463 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5464 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5465
5466 data = (data << 16) | (pdevice->Period << 8) | 10;
5467 ioc->spi_data.nvram[ii] = data;
5468 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469 } else {
5470 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5471 MpiDeviceInfo_t *pdevice = NULL;
5472
Moore, Ericd8e925d2006-01-16 18:53:06 -07005473 /*
5474 * Save "Set to Avoid SCSI Bus Resets" flag
5475 */
5476 ioc->spi_data.bus_reset =
5477 (le32_to_cpu(pPP2->PortFlags) &
5478 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5479 0 : 1 ;
5480
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481 /* Save the Port Page 2 data
5482 * (reformat into a 32bit quantity)
5483 */
5484 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5485 ioc->spi_data.PortFlags = data;
5486 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5487 pdevice = &pPP2->DeviceSettings[ii];
5488 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5489 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5490 ioc->spi_data.nvram[ii] = data;
5491 }
5492 }
5493
5494 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5495 }
5496 }
5497
5498 /* Update Adapter limits with those from NVRAM
5499 * Comment: Don't need to do this. Target performance
5500 * parameters will never exceed the adapters limits.
5501 */
5502
5503 return rc;
5504}
5505
5506/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005507/**
5508 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 * @ioc: Pointer to a Adapter Strucutre
5510 * @portnum: IOC port number
5511 *
5512 * Return: -EFAULT if read of config page header fails
5513 * or 0 if success.
5514 */
5515static int
5516mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5517{
5518 CONFIGPARMS cfg;
5519 ConfigPageHeader_t header;
5520
5521 /* Read the SCSI Device Page 1 header
5522 */
5523 header.PageVersion = 0;
5524 header.PageLength = 0;
5525 header.PageNumber = 1;
5526 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005527 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528 cfg.physAddr = -1;
5529 cfg.pageAddr = portnum;
5530 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5531 cfg.dir = 0;
5532 cfg.timeout = 0;
5533 if (mpt_config(ioc, &cfg) != 0)
5534 return -EFAULT;
5535
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005536 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5537 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538
5539 header.PageVersion = 0;
5540 header.PageLength = 0;
5541 header.PageNumber = 0;
5542 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5543 if (mpt_config(ioc, &cfg) != 0)
5544 return -EFAULT;
5545
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005546 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5547 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005548
Prakash, Sathya436ace72007-07-24 15:42:08 +05305549 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5551
Prakash, Sathya436ace72007-07-24 15:42:08 +05305552 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5554 return 0;
5555}
5556
Eric Mooreb506ade2007-01-29 09:45:37 -07005557/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005558 * mpt_inactive_raid_list_free - This clears this link list.
5559 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005560 **/
5561static void
5562mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5563{
5564 struct inactive_raid_component_info *component_info, *pNext;
5565
5566 if (list_empty(&ioc->raid_data.inactive_list))
5567 return;
5568
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005569 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005570 list_for_each_entry_safe(component_info, pNext,
5571 &ioc->raid_data.inactive_list, list) {
5572 list_del(&component_info->list);
5573 kfree(component_info);
5574 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005575 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005576}
5577
5578/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005579 * 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 -07005580 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005581 * @ioc : pointer to per adapter structure
5582 * @channel : volume channel
5583 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005584 **/
5585static void
5586mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5587{
5588 CONFIGPARMS cfg;
5589 ConfigPageHeader_t hdr;
5590 dma_addr_t dma_handle;
5591 pRaidVolumePage0_t buffer = NULL;
5592 int i;
5593 RaidPhysDiskPage0_t phys_disk;
5594 struct inactive_raid_component_info *component_info;
5595 int handle_inactive_volumes;
5596
5597 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5598 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5599 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5600 cfg.pageAddr = (channel << 8) + id;
5601 cfg.cfghdr.hdr = &hdr;
5602 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5603
5604 if (mpt_config(ioc, &cfg) != 0)
5605 goto out;
5606
5607 if (!hdr.PageLength)
5608 goto out;
5609
5610 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5611 &dma_handle);
5612
5613 if (!buffer)
5614 goto out;
5615
5616 cfg.physAddr = dma_handle;
5617 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5618
5619 if (mpt_config(ioc, &cfg) != 0)
5620 goto out;
5621
5622 if (!buffer->NumPhysDisks)
5623 goto out;
5624
5625 handle_inactive_volumes =
5626 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5627 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5628 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5629 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5630
5631 if (!handle_inactive_volumes)
5632 goto out;
5633
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005634 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005635 for (i = 0; i < buffer->NumPhysDisks; i++) {
5636 if(mpt_raid_phys_disk_pg0(ioc,
5637 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5638 continue;
5639
5640 if ((component_info = kmalloc(sizeof (*component_info),
5641 GFP_KERNEL)) == NULL)
5642 continue;
5643
5644 component_info->volumeID = id;
5645 component_info->volumeBus = channel;
5646 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5647 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5648 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5649 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5650
5651 list_add_tail(&component_info->list,
5652 &ioc->raid_data.inactive_list);
5653 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005654 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005655
5656 out:
5657 if (buffer)
5658 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5659 dma_handle);
5660}
5661
5662/**
5663 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5664 * @ioc: Pointer to a Adapter Structure
5665 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5666 * @phys_disk: requested payload data returned
5667 *
5668 * Return:
5669 * 0 on success
5670 * -EFAULT if read of config page header fails or data pointer not NULL
5671 * -ENOMEM if pci_alloc failed
5672 **/
5673int
Kashyap, Desai2f187862009-05-29 16:52:37 +05305674mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
5675 RaidPhysDiskPage0_t *phys_disk)
Eric Mooreb506ade2007-01-29 09:45:37 -07005676{
Kashyap, Desai2f187862009-05-29 16:52:37 +05305677 CONFIGPARMS cfg;
5678 ConfigPageHeader_t hdr;
Eric Mooreb506ade2007-01-29 09:45:37 -07005679 dma_addr_t dma_handle;
5680 pRaidPhysDiskPage0_t buffer = NULL;
5681 int rc;
5682
5683 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5684 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
Kashyap, Desai2f187862009-05-29 16:52:37 +05305685 memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
Eric Mooreb506ade2007-01-29 09:45:37 -07005686
Kashyap, Desai2f187862009-05-29 16:52:37 +05305687 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
Eric Mooreb506ade2007-01-29 09:45:37 -07005688 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5689 cfg.cfghdr.hdr = &hdr;
5690 cfg.physAddr = -1;
5691 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5692
5693 if (mpt_config(ioc, &cfg) != 0) {
5694 rc = -EFAULT;
5695 goto out;
5696 }
5697
5698 if (!hdr.PageLength) {
5699 rc = -EFAULT;
5700 goto out;
5701 }
5702
5703 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5704 &dma_handle);
5705
5706 if (!buffer) {
5707 rc = -ENOMEM;
5708 goto out;
5709 }
5710
5711 cfg.physAddr = dma_handle;
5712 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5713 cfg.pageAddr = phys_disk_num;
5714
5715 if (mpt_config(ioc, &cfg) != 0) {
5716 rc = -EFAULT;
5717 goto out;
5718 }
5719
5720 rc = 0;
5721 memcpy(phys_disk, buffer, sizeof(*buffer));
5722 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5723
5724 out:
5725
5726 if (buffer)
5727 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5728 dma_handle);
5729
5730 return rc;
5731}
5732
Linus Torvalds1da177e2005-04-16 15:20:36 -07005733/**
Kashyap, Desaia7938b02009-05-29 16:53:56 +05305734 * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
5735 * @ioc: Pointer to a Adapter Structure
5736 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5737 *
5738 * Return:
5739 * returns number paths
5740 **/
5741int
5742mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
5743{
5744 CONFIGPARMS cfg;
5745 ConfigPageHeader_t hdr;
5746 dma_addr_t dma_handle;
5747 pRaidPhysDiskPage1_t buffer = NULL;
5748 int rc;
5749
5750 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5751 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5752
5753 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5754 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5755 hdr.PageNumber = 1;
5756 cfg.cfghdr.hdr = &hdr;
5757 cfg.physAddr = -1;
5758 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5759
5760 if (mpt_config(ioc, &cfg) != 0) {
5761 rc = 0;
5762 goto out;
5763 }
5764
5765 if (!hdr.PageLength) {
5766 rc = 0;
5767 goto out;
5768 }
5769
5770 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5771 &dma_handle);
5772
5773 if (!buffer) {
5774 rc = 0;
5775 goto out;
5776 }
5777
5778 cfg.physAddr = dma_handle;
5779 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5780 cfg.pageAddr = phys_disk_num;
5781
5782 if (mpt_config(ioc, &cfg) != 0) {
5783 rc = 0;
5784 goto out;
5785 }
5786
5787 rc = buffer->NumPhysDiskPaths;
5788 out:
5789
5790 if (buffer)
5791 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5792 dma_handle);
5793
5794 return rc;
5795}
5796EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
5797
5798/**
5799 * mpt_raid_phys_disk_pg1 - returns phys disk page 1
5800 * @ioc: Pointer to a Adapter Structure
5801 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5802 * @phys_disk: requested payload data returned
5803 *
5804 * Return:
5805 * 0 on success
5806 * -EFAULT if read of config page header fails or data pointer not NULL
5807 * -ENOMEM if pci_alloc failed
5808 **/
5809int
5810mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
5811 RaidPhysDiskPage1_t *phys_disk)
5812{
5813 CONFIGPARMS cfg;
5814 ConfigPageHeader_t hdr;
5815 dma_addr_t dma_handle;
5816 pRaidPhysDiskPage1_t buffer = NULL;
5817 int rc;
5818 int i;
5819 __le64 sas_address;
5820
5821 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5822 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5823 rc = 0;
5824
5825 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5826 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5827 hdr.PageNumber = 1;
5828 cfg.cfghdr.hdr = &hdr;
5829 cfg.physAddr = -1;
5830 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5831
5832 if (mpt_config(ioc, &cfg) != 0) {
5833 rc = -EFAULT;
5834 goto out;
5835 }
5836
5837 if (!hdr.PageLength) {
5838 rc = -EFAULT;
5839 goto out;
5840 }
5841
5842 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5843 &dma_handle);
5844
5845 if (!buffer) {
5846 rc = -ENOMEM;
5847 goto out;
5848 }
5849
5850 cfg.physAddr = dma_handle;
5851 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5852 cfg.pageAddr = phys_disk_num;
5853
5854 if (mpt_config(ioc, &cfg) != 0) {
5855 rc = -EFAULT;
5856 goto out;
5857 }
5858
5859 phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
5860 phys_disk->PhysDiskNum = phys_disk_num;
5861 for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
5862 phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
5863 phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
5864 phys_disk->Path[i].OwnerIdentifier =
5865 buffer->Path[i].OwnerIdentifier;
5866 phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
5867 memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
5868 sas_address = le64_to_cpu(sas_address);
5869 memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
5870 memcpy(&sas_address,
5871 &buffer->Path[i].OwnerWWID, sizeof(__le64));
5872 sas_address = le64_to_cpu(sas_address);
5873 memcpy(&phys_disk->Path[i].OwnerWWID,
5874 &sas_address, sizeof(__le64));
5875 }
5876
5877 out:
5878
5879 if (buffer)
5880 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5881 dma_handle);
5882
5883 return rc;
5884}
5885EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
5886
5887
5888/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5890 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891 *
5892 * Return:
5893 * 0 on success
5894 * -EFAULT if read of config page header fails or data pointer not NULL
5895 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005896 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005897int
5898mpt_findImVolumes(MPT_ADAPTER *ioc)
5899{
5900 IOCPage2_t *pIoc2;
5901 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902 dma_addr_t ioc2_dma;
5903 CONFIGPARMS cfg;
5904 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005905 int rc = 0;
5906 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005907 int i;
5908
5909 if (!ioc->ir_firmware)
5910 return 0;
5911
5912 /* Free the old page
5913 */
5914 kfree(ioc->raid_data.pIocPg2);
5915 ioc->raid_data.pIocPg2 = NULL;
5916 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005917
5918 /* Read IOCP2 header then the page.
5919 */
5920 header.PageVersion = 0;
5921 header.PageLength = 0;
5922 header.PageNumber = 2;
5923 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005924 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005925 cfg.physAddr = -1;
5926 cfg.pageAddr = 0;
5927 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5928 cfg.dir = 0;
5929 cfg.timeout = 0;
5930 if (mpt_config(ioc, &cfg) != 0)
5931 return -EFAULT;
5932
5933 if (header.PageLength == 0)
5934 return -EFAULT;
5935
5936 iocpage2sz = header.PageLength * 4;
5937 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5938 if (!pIoc2)
5939 return -ENOMEM;
5940
5941 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5942 cfg.physAddr = ioc2_dma;
5943 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005944 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005945
Eric Mooreb506ade2007-01-29 09:45:37 -07005946 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5947 if (!mem)
5948 goto out;
5949
Linus Torvalds1da177e2005-04-16 15:20:36 -07005950 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005951 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005952
Eric Mooreb506ade2007-01-29 09:45:37 -07005953 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005954
Eric Mooreb506ade2007-01-29 09:45:37 -07005955 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5956 mpt_inactive_raid_volumes(ioc,
5957 pIoc2->RaidVolume[i].VolumeBus,
5958 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959
Eric Mooreb506ade2007-01-29 09:45:37 -07005960 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005961 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5962
5963 return rc;
5964}
5965
Moore, Ericc972c702006-03-14 09:14:06 -07005966static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5968{
5969 IOCPage3_t *pIoc3;
5970 u8 *mem;
5971 CONFIGPARMS cfg;
5972 ConfigPageHeader_t header;
5973 dma_addr_t ioc3_dma;
5974 int iocpage3sz = 0;
5975
5976 /* Free the old page
5977 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005978 kfree(ioc->raid_data.pIocPg3);
5979 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980
5981 /* There is at least one physical disk.
5982 * Read and save IOC Page 3
5983 */
5984 header.PageVersion = 0;
5985 header.PageLength = 0;
5986 header.PageNumber = 3;
5987 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005988 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005989 cfg.physAddr = -1;
5990 cfg.pageAddr = 0;
5991 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5992 cfg.dir = 0;
5993 cfg.timeout = 0;
5994 if (mpt_config(ioc, &cfg) != 0)
5995 return 0;
5996
5997 if (header.PageLength == 0)
5998 return 0;
5999
6000 /* Read Header good, alloc memory
6001 */
6002 iocpage3sz = header.PageLength * 4;
6003 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
6004 if (!pIoc3)
6005 return 0;
6006
6007 /* Read the Page and save the data
6008 * into malloc'd memory.
6009 */
6010 cfg.physAddr = ioc3_dma;
6011 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6012 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07006013 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006014 if (mem) {
6015 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006016 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006017 }
6018 }
6019
6020 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
6021
6022 return 0;
6023}
6024
6025static void
6026mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
6027{
6028 IOCPage4_t *pIoc4;
6029 CONFIGPARMS cfg;
6030 ConfigPageHeader_t header;
6031 dma_addr_t ioc4_dma;
6032 int iocpage4sz;
6033
6034 /* Read and save IOC Page 4
6035 */
6036 header.PageVersion = 0;
6037 header.PageLength = 0;
6038 header.PageNumber = 4;
6039 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006040 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041 cfg.physAddr = -1;
6042 cfg.pageAddr = 0;
6043 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6044 cfg.dir = 0;
6045 cfg.timeout = 0;
6046 if (mpt_config(ioc, &cfg) != 0)
6047 return;
6048
6049 if (header.PageLength == 0)
6050 return;
6051
6052 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
6053 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
6054 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
6055 if (!pIoc4)
6056 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06006057 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006058 } else {
6059 ioc4_dma = ioc->spi_data.IocPg4_dma;
6060 iocpage4sz = ioc->spi_data.IocPg4Sz;
6061 }
6062
6063 /* Read the Page into dma memory.
6064 */
6065 cfg.physAddr = ioc4_dma;
6066 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6067 if (mpt_config(ioc, &cfg) == 0) {
6068 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
6069 ioc->spi_data.IocPg4_dma = ioc4_dma;
6070 ioc->spi_data.IocPg4Sz = iocpage4sz;
6071 } else {
6072 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
6073 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06006074 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006075 }
6076}
6077
6078static void
6079mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
6080{
6081 IOCPage1_t *pIoc1;
6082 CONFIGPARMS cfg;
6083 ConfigPageHeader_t header;
6084 dma_addr_t ioc1_dma;
6085 int iocpage1sz = 0;
6086 u32 tmp;
6087
6088 /* Check the Coalescing Timeout in IOC Page 1
6089 */
6090 header.PageVersion = 0;
6091 header.PageLength = 0;
6092 header.PageNumber = 1;
6093 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006094 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006095 cfg.physAddr = -1;
6096 cfg.pageAddr = 0;
6097 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6098 cfg.dir = 0;
6099 cfg.timeout = 0;
6100 if (mpt_config(ioc, &cfg) != 0)
6101 return;
6102
6103 if (header.PageLength == 0)
6104 return;
6105
6106 /* Read Header good, alloc memory
6107 */
6108 iocpage1sz = header.PageLength * 4;
6109 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
6110 if (!pIoc1)
6111 return;
6112
6113 /* Read the Page and check coalescing timeout
6114 */
6115 cfg.physAddr = ioc1_dma;
6116 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6117 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306118
Linus Torvalds1da177e2005-04-16 15:20:36 -07006119 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
6120 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
6121 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
6122
Prakash, Sathya436ace72007-07-24 15:42:08 +05306123 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006124 ioc->name, tmp));
6125
6126 if (tmp > MPT_COALESCING_TIMEOUT) {
6127 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
6128
6129 /* Write NVRAM and current
6130 */
6131 cfg.dir = 1;
6132 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
6133 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306134 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135 ioc->name, MPT_COALESCING_TIMEOUT));
6136
6137 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
6138 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306139 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6140 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141 ioc->name, MPT_COALESCING_TIMEOUT));
6142 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306143 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6144 "Reset NVRAM Coalescing Timeout Failed\n",
6145 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006146 }
6147
6148 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306149 dprintk(ioc, printk(MYIOC_s_WARN_FMT
6150 "Reset of Current Coalescing Timeout Failed!\n",
6151 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006152 }
6153 }
6154
6155 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306156 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006157 }
6158 }
6159
6160 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
6161
6162 return;
6163}
6164
Prakash, Sathyaedb90682007-07-17 14:39:14 +05306165static void
6166mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
6167{
6168 CONFIGPARMS cfg;
6169 ConfigPageHeader_t hdr;
6170 dma_addr_t buf_dma;
6171 ManufacturingPage0_t *pbuf = NULL;
6172
6173 memset(&cfg, 0 , sizeof(CONFIGPARMS));
6174 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
6175
6176 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
6177 cfg.cfghdr.hdr = &hdr;
6178 cfg.physAddr = -1;
6179 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6180 cfg.timeout = 10;
6181
6182 if (mpt_config(ioc, &cfg) != 0)
6183 goto out;
6184
6185 if (!cfg.cfghdr.hdr->PageLength)
6186 goto out;
6187
6188 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6189 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
6190 if (!pbuf)
6191 goto out;
6192
6193 cfg.physAddr = buf_dma;
6194
6195 if (mpt_config(ioc, &cfg) != 0)
6196 goto out;
6197
6198 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
6199 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
6200 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
6201
6202 out:
6203
6204 if (pbuf)
6205 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
6206}
6207
Linus Torvalds1da177e2005-04-16 15:20:36 -07006208/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006209/**
6210 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211 * @ioc: Pointer to MPT_ADAPTER structure
6212 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05306213 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07006214 */
6215static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05306216SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217{
Kashyap, Desaifd761752009-05-29 16:39:06 +05306218 EventNotification_t evn;
6219 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006220
Kashyap, Desaifd761752009-05-29 16:39:06 +05306221 memset(&evn, 0, sizeof(EventNotification_t));
6222 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223
Kashyap, Desaifd761752009-05-29 16:39:06 +05306224 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
6225 evn.Switch = EvSwitch;
6226 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006227
Kashyap, Desaifd761752009-05-29 16:39:06 +05306228 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6229 "Sending EventNotification (%d) request %p\n",
6230 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006231
Kashyap, Desaifd761752009-05-29 16:39:06 +05306232 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6233 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6234 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006235}
6236
6237/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6238/**
6239 * SendEventAck - Send EventAck request to MPT adapter.
6240 * @ioc: Pointer to MPT_ADAPTER structure
6241 * @evnp: Pointer to original EventNotification request
6242 */
6243static int
6244SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6245{
6246 EventAck_t *pAck;
6247
6248 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306249 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306250 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251 return -1;
6252 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006253
Prakash, Sathya436ace72007-07-24 15:42:08 +05306254 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006255
6256 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6257 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006258 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006259 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006260 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006261 pAck->Event = evnp->Event;
6262 pAck->EventContext = evnp->EventContext;
6263
6264 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6265
6266 return 0;
6267}
6268
6269/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6270/**
6271 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006272 * @ioc: Pointer to an adapter structure
6273 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274 * action, page address, direction, physical address
6275 * and pointer to a configuration page header
6276 * Page header is updated.
6277 *
6278 * Returns 0 for success
6279 * -EPERM if not allowed due to ISR context
6280 * -EAGAIN if no msg frames currently available
6281 * -EFAULT for non-successful reply or no reply (timeout)
6282 */
6283int
6284mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6285{
6286 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306287 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006288 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006289 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306290 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006291 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306292 long timeout;
6293 int ret;
6294 u8 page_type = 0, extend_page;
6295 unsigned long timeleft;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306296 unsigned long flags;
6297 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306298 u8 issue_hard_reset = 0;
6299 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006300
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006301 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006302 * to be in ISR context, because that is fatal!
6303 */
6304 in_isr = in_interrupt();
6305 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306306 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006307 ioc->name));
6308 return -EPERM;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306309 }
6310
6311 /* don't send a config page during diag reset */
6312 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6313 if (ioc->ioc_reset_in_progress) {
6314 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6315 "%s: busy with host reset\n", ioc->name, __func__));
6316 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6317 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006318 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306319 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006320
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306321 /* don't send if no chance of success */
6322 if (!ioc->active ||
6323 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6324 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6325 "%s: ioc not operational, %d, %xh\n",
6326 ioc->name, __func__, ioc->active,
6327 mpt_GetIocState(ioc, 0)));
6328 return -EFAULT;
6329 }
6330
6331 retry_config:
6332 mutex_lock(&ioc->mptbase_cmds.mutex);
6333 /* init the internal cmd struct */
6334 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6335 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6336
Linus Torvalds1da177e2005-04-16 15:20:36 -07006337 /* Get and Populate a free Frame
6338 */
6339 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306340 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6341 "mpt_config: no msg frames!\n", ioc->name));
6342 ret = -EAGAIN;
6343 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006344 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306345
Linus Torvalds1da177e2005-04-16 15:20:36 -07006346 pReq = (Config_t *)mf;
6347 pReq->Action = pCfg->action;
6348 pReq->Reserved = 0;
6349 pReq->ChainOffset = 0;
6350 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006351
6352 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006353 pReq->ExtPageLength = 0;
6354 pReq->ExtPageType = 0;
6355 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006356
Linus Torvalds1da177e2005-04-16 15:20:36 -07006357 for (ii=0; ii < 8; ii++)
6358 pReq->Reserved2[ii] = 0;
6359
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006360 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6361 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6362 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6363 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6364
6365 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6366 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6367 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6368 pReq->ExtPageType = pExtHdr->ExtPageType;
6369 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6370
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306371 /* Page Length must be treated as a reserved field for the
6372 * extended header.
6373 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006374 pReq->Header.PageLength = 0;
6375 }
6376
Linus Torvalds1da177e2005-04-16 15:20:36 -07006377 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6378
6379 /* Add a SGE to the config request.
6380 */
6381 if (pCfg->dir)
6382 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6383 else
6384 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6385
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306386 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6387 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006388 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306389 page_type = pReq->ExtPageType;
6390 extend_page = 1;
6391 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006392 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306393 page_type = pReq->Header.PageType;
6394 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006395 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006396
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306397 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6398 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6399 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6400
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306401 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306402 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006403 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306404 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6405 timeout);
6406 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6407 ret = -ETIME;
6408 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6409 "Failed Sending Config request type 0x%x, page 0x%x,"
6410 " action %d, status %xh, time left %ld\n\n",
6411 ioc->name, page_type, pReq->Header.PageNumber,
6412 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6413 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6414 goto out;
6415 if (!timeleft)
6416 issue_hard_reset = 1;
6417 goto out;
6418 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006419
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306420 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6421 ret = -1;
6422 goto out;
6423 }
6424 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6425 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6426 if (ret == MPI_IOCSTATUS_SUCCESS) {
6427 if (extend_page) {
6428 pCfg->cfghdr.ehdr->ExtPageLength =
6429 le16_to_cpu(pReply->ExtPageLength);
6430 pCfg->cfghdr.ehdr->ExtPageType =
6431 pReply->ExtPageType;
6432 }
6433 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6434 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6435 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6436 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006437
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306438 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006439
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306440 if (retry_count)
6441 printk(MYIOC_s_INFO_FMT "Retry completed "
6442 "ret=0x%x timeleft=%ld\n",
6443 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006444
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306445 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6446 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006447
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306448out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006449
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306450 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6451 mutex_unlock(&ioc->mptbase_cmds.mutex);
6452 if (issue_hard_reset) {
6453 issue_hard_reset = 0;
6454 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
6455 ioc->name, __func__);
6456 mpt_HardResetHandler(ioc, CAN_SLEEP);
6457 mpt_free_msg_frame(ioc, mf);
6458 /* attempt one retry for a timed out command */
6459 if (!retry_count) {
6460 printk(MYIOC_s_INFO_FMT
6461 "Attempting Retry Config request"
6462 " type 0x%x, page 0x%x,"
6463 " action %d\n", ioc->name, page_type,
6464 pCfg->cfghdr.hdr->PageNumber, pCfg->action);
6465 retry_count++;
6466 goto retry_config;
6467 }
6468 }
6469 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006470
Linus Torvalds1da177e2005-04-16 15:20:36 -07006471}
6472
6473/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006474/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006475 * mpt_ioc_reset - Base cleanup for hard reset
6476 * @ioc: Pointer to the adapter structure
6477 * @reset_phase: Indicates pre- or post-reset functionality
6478 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006479 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006480 */
6481static int
6482mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6483{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306484 switch (reset_phase) {
6485 case MPT_IOC_SETUP_RESET:
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306486 ioc->taskmgmt_quiesce_io = 1;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306487 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6488 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
6489 break;
6490 case MPT_IOC_PRE_RESET:
6491 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6492 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
6493 break;
6494 case MPT_IOC_POST_RESET:
6495 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6496 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
6497/* wake up mptbase_cmds */
6498 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6499 ioc->mptbase_cmds.status |=
6500 MPT_MGMT_STATUS_DID_IOCRESET;
6501 complete(&ioc->mptbase_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006502 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306503/* wake up taskmgmt_cmds */
6504 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
6505 ioc->taskmgmt_cmds.status |=
6506 MPT_MGMT_STATUS_DID_IOCRESET;
6507 complete(&ioc->taskmgmt_cmds.done);
6508 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306509 break;
6510 default:
6511 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006512 }
6513
6514 return 1; /* currently means nothing really */
6515}
6516
6517
6518#ifdef CONFIG_PROC_FS /* { */
6519/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6520/*
6521 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6522 */
6523/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006524/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006525 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6526 *
6527 * Returns 0 for success, non-zero for failure.
6528 */
6529static int
6530procmpt_create(void)
6531{
6532 struct proc_dir_entry *ent;
6533
6534 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6535 if (mpt_proc_root_dir == NULL)
6536 return -ENOTDIR;
6537
6538 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6539 if (ent)
6540 ent->read_proc = procmpt_summary_read;
6541
6542 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6543 if (ent)
6544 ent->read_proc = procmpt_version_read;
6545
6546 return 0;
6547}
6548
6549/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006550/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006551 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6552 *
6553 * Returns 0 for success, non-zero for failure.
6554 */
6555static void
6556procmpt_destroy(void)
6557{
6558 remove_proc_entry("version", mpt_proc_root_dir);
6559 remove_proc_entry("summary", mpt_proc_root_dir);
6560 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6561}
6562
6563/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006564/**
6565 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006566 * @buf: Pointer to area to write information
6567 * @start: Pointer to start pointer
6568 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006569 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006570 * @eof: Pointer to EOF integer
6571 * @data: Pointer
6572 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006573 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006574 * Returns number of characters written to process performing the read.
6575 */
6576static int
6577procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6578{
6579 MPT_ADAPTER *ioc;
6580 char *out = buf;
6581 int len;
6582
6583 if (data) {
6584 int more = 0;
6585
6586 ioc = data;
6587 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6588
6589 out += more;
6590 } else {
6591 list_for_each_entry(ioc, &ioc_list, list) {
6592 int more = 0;
6593
6594 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6595
6596 out += more;
6597 if ((out-buf) >= request)
6598 break;
6599 }
6600 }
6601
6602 len = out - buf;
6603
6604 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6605}
6606
6607/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006608/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006609 * procmpt_version_read - Handle read request from /proc/mpt/version.
6610 * @buf: Pointer to area to write information
6611 * @start: Pointer to start pointer
6612 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006613 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006614 * @eof: Pointer to EOF integer
6615 * @data: Pointer
6616 *
6617 * Returns number of characters written to process performing the read.
6618 */
6619static int
6620procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6621{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306622 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006623 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006624 char *drvname;
6625 int len;
6626
6627 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6628 len += sprintf(buf+len, " Fusion MPT base driver\n");
6629
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006630 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006631 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006632 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306633 if (MptCallbacks[cb_idx]) {
6634 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006635 case MPTSPI_DRIVER:
6636 if (!scsi++) drvname = "SPI host";
6637 break;
6638 case MPTFC_DRIVER:
6639 if (!fc++) drvname = "FC host";
6640 break;
6641 case MPTSAS_DRIVER:
6642 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006643 break;
6644 case MPTLAN_DRIVER:
6645 if (!lan++) drvname = "LAN";
6646 break;
6647 case MPTSTM_DRIVER:
6648 if (!targ++) drvname = "SCSI target";
6649 break;
6650 case MPTCTL_DRIVER:
6651 if (!ctl++) drvname = "ioctl";
6652 break;
6653 }
6654
6655 if (drvname)
6656 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6657 }
6658 }
6659
6660 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6661}
6662
6663/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006664/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006665 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6666 * @buf: Pointer to area to write information
6667 * @start: Pointer to start pointer
6668 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006669 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006670 * @eof: Pointer to EOF integer
6671 * @data: Pointer
6672 *
6673 * Returns number of characters written to process performing the read.
6674 */
6675static int
6676procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6677{
6678 MPT_ADAPTER *ioc = data;
6679 int len;
6680 char expVer[32];
6681 int sz;
6682 int p;
6683
6684 mpt_get_fw_exp_ver(expVer, ioc);
6685
6686 len = sprintf(buf, "%s:", ioc->name);
6687 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6688 len += sprintf(buf+len, " (f/w download boot flag set)");
6689// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6690// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6691
6692 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6693 ioc->facts.ProductID,
6694 ioc->prod_name);
6695 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6696 if (ioc->facts.FWImageSize)
6697 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6698 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6699 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6700 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6701
6702 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6703 ioc->facts.CurrentHostMfaHighAddr);
6704 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6705 ioc->facts.CurrentSenseBufferHighAddr);
6706
6707 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6708 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6709
6710 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6711 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6712 /*
6713 * Rounding UP to nearest 4-kB boundary here...
6714 */
6715 sz = (ioc->req_sz * ioc->req_depth) + 128;
6716 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6717 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6718 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6719 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6720 4*ioc->facts.RequestFrameSize,
6721 ioc->facts.GlobalCredits);
6722
6723 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6724 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6725 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6726 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6727 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6728 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6729 ioc->facts.CurReplyFrameSize,
6730 ioc->facts.ReplyQueueDepth);
6731
6732 len += sprintf(buf+len, " MaxDevices = %d\n",
6733 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6734 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6735
6736 /* per-port info */
6737 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6738 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6739 p+1,
6740 ioc->facts.NumberOfPorts);
6741 if (ioc->bus_type == FC) {
6742 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6743 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6744 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6745 a[5], a[4], a[3], a[2], a[1], a[0]);
6746 }
6747 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6748 ioc->fc_port_page0[p].WWNN.High,
6749 ioc->fc_port_page0[p].WWNN.Low,
6750 ioc->fc_port_page0[p].WWPN.High,
6751 ioc->fc_port_page0[p].WWPN.Low);
6752 }
6753 }
6754
6755 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6756}
6757
6758#endif /* CONFIG_PROC_FS } */
6759
6760/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6761static void
6762mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6763{
6764 buf[0] ='\0';
6765 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6766 sprintf(buf, " (Exp %02d%02d)",
6767 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6768 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6769
6770 /* insider hack! */
6771 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6772 strcat(buf, " [MDBG]");
6773 }
6774}
6775
6776/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6777/**
6778 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6779 * @ioc: Pointer to MPT_ADAPTER structure
6780 * @buffer: Pointer to buffer where IOC summary info should be written
6781 * @size: Pointer to number of bytes we wrote (set by this routine)
6782 * @len: Offset at which to start writing in buffer
6783 * @showlan: Display LAN stuff?
6784 *
6785 * This routine writes (english readable) ASCII text, which represents
6786 * a summary of IOC information, to a buffer.
6787 */
6788void
6789mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6790{
6791 char expVer[32];
6792 int y;
6793
6794 mpt_get_fw_exp_ver(expVer, ioc);
6795
6796 /*
6797 * Shorter summary of attached ioc's...
6798 */
6799 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6800 ioc->name,
6801 ioc->prod_name,
6802 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6803 ioc->facts.FWVersion.Word,
6804 expVer,
6805 ioc->facts.NumberOfPorts,
6806 ioc->req_depth);
6807
6808 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6809 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6810 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6811 a[5], a[4], a[3], a[2], a[1], a[0]);
6812 }
6813
Linus Torvalds1da177e2005-04-16 15:20:36 -07006814 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006815
6816 if (!ioc->active)
6817 y += sprintf(buffer+len+y, " (disabled)");
6818
6819 y += sprintf(buffer+len+y, "\n");
6820
6821 *size = y;
6822}
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306823/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006824 * mpt_set_taskmgmt_in_progress_flag - set flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306825 * @ioc: Pointer to MPT_ADAPTER structure
6826 *
6827 * Returns 0 for SUCCESS or -1 if FAILED.
6828 *
6829 * If -1 is return, then it was not possible to set the flags
6830 **/
6831int
6832mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6833{
6834 unsigned long flags;
6835 int retval;
6836
6837 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6838 if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
6839 (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
6840 retval = -1;
6841 goto out;
6842 }
6843 retval = 0;
6844 ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306845 ioc->taskmgmt_quiesce_io = 1;
6846 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306847 ioc->alt_ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306848 ioc->alt_ioc->taskmgmt_quiesce_io = 1;
6849 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306850 out:
6851 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6852 return retval;
6853}
6854EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
6855
6856/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006857 * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306858 * @ioc: Pointer to MPT_ADAPTER structure
6859 *
6860 **/
6861void
6862mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6863{
6864 unsigned long flags;
6865
6866 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6867 ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306868 ioc->taskmgmt_quiesce_io = 0;
6869 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306870 ioc->alt_ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306871 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
6872 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306873 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6874}
6875EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006876
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306877
6878/**
6879 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6880 * the kernel
6881 * @ioc: Pointer to MPT_ADAPTER structure
6882 *
6883 **/
6884void
6885mpt_halt_firmware(MPT_ADAPTER *ioc)
6886{
6887 u32 ioc_raw_state;
6888
6889 ioc_raw_state = mpt_GetIocState(ioc, 0);
6890
6891 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6892 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6893 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6894 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6895 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6896 } else {
6897 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6898 panic("%s: Firmware is halted due to command timeout\n",
6899 ioc->name);
6900 }
6901}
6902EXPORT_SYMBOL(mpt_halt_firmware);
6903
Linus Torvalds1da177e2005-04-16 15:20:36 -07006904/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6905/*
6906 * Reset Handling
6907 */
6908/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6909/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006910 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006911 * @ioc: Pointer to MPT_ADAPTER structure
6912 * @sleepFlag: Indicates if sleep or schedule must be called.
6913 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006914 * Issues SCSI Task Management call based on input arg values.
6915 * If TaskMgmt fails, returns associated SCSI request.
6916 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006917 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6918 * or a non-interrupt thread. In the former, must not call schedule().
6919 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006920 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006921 * FW reload/initialization failed.
6922 *
6923 * Returns 0 for SUCCESS or -1 if FAILED.
6924 */
6925int
6926mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6927{
Kashyap, Desaid1306912009-08-05 12:53:51 +05306928 int rc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306929 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006930 unsigned long flags;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306931 unsigned long time_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006932
Prakash, Sathya436ace72007-07-24 15:42:08 +05306933 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006934#ifdef MFCNT
6935 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6936 printk("MF count 0x%x !\n", ioc->mfcnt);
6937#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306938 if (mpt_fwfault_debug)
6939 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006940
6941 /* Reset the adapter. Prevent more than 1 call to
6942 * mpt_do_ioc_recovery at any instant in time.
6943 */
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306944 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6945 if (ioc->ioc_reset_in_progress) {
6946 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006947 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006948 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306949 ioc->ioc_reset_in_progress = 1;
6950 if (ioc->alt_ioc)
6951 ioc->alt_ioc->ioc_reset_in_progress = 1;
6952 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006953
Linus Torvalds1da177e2005-04-16 15:20:36 -07006954
6955 /* The SCSI driver needs to adjust timeouts on all current
6956 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006957 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006958 * For all other protocol drivers, this is a no-op.
6959 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05306960 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6961 if (MptResetHandlers[cb_idx]) {
6962 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
6963 if (ioc->alt_ioc)
6964 mpt_signal_reset(cb_idx, ioc->alt_ioc,
6965 MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006966 }
6967 }
6968
Kashyap, Desai2f187862009-05-29 16:52:37 +05306969 time_count = jiffies;
6970 rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
6971 if (rc != 0) {
6972 printk(KERN_WARNING MYNAM
6973 ": WARNING - (%d) Cannot recover %s\n", rc, ioc->name);
6974 } else {
6975 if (ioc->hard_resets < -1)
6976 ioc->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006977 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006978
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306979 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6980 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306981 ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306982 ioc->taskmgmt_in_progress = 0;
6983 if (ioc->alt_ioc) {
6984 ioc->alt_ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306985 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306986 ioc->alt_ioc->taskmgmt_in_progress = 0;
6987 }
6988 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006989
Kashyap, Desaid1306912009-08-05 12:53:51 +05306990 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6991 if (MptResetHandlers[cb_idx]) {
6992 mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
6993 if (ioc->alt_ioc)
6994 mpt_signal_reset(cb_idx,
6995 ioc->alt_ioc, MPT_IOC_POST_RESET);
6996 }
6997 }
6998
Kashyap, Desai2f187862009-05-29 16:52:37 +05306999 dtmprintk(ioc,
7000 printk(MYIOC_s_DEBUG_FMT
7001 "HardResetHandler: completed (%d seconds): %s\n", ioc->name,
7002 jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?
7003 "SUCCESS" : "FAILED")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007004
7005 return rc;
7006}
7007
Kashyap, Desai2f187862009-05-29 16:52:37 +05307008#ifdef CONFIG_FUSION_LOGGING
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007009static void
Kashyap, Desai2f187862009-05-29 16:52:37 +05307010mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007011{
Eric Moore509e5e52006-04-26 13:22:37 -06007012 char *ds = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307013 u32 evData0;
7014 int ii;
7015 u8 event;
7016 char *evStr = ioc->evStr;
7017
7018 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7019 evData0 = le32_to_cpu(pEventReply->Data[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007020
7021 switch(event) {
7022 case MPI_EVENT_NONE:
7023 ds = "None";
7024 break;
7025 case MPI_EVENT_LOG_DATA:
7026 ds = "Log Data";
7027 break;
7028 case MPI_EVENT_STATE_CHANGE:
7029 ds = "State Change";
7030 break;
7031 case MPI_EVENT_UNIT_ATTENTION:
7032 ds = "Unit Attention";
7033 break;
7034 case MPI_EVENT_IOC_BUS_RESET:
7035 ds = "IOC Bus Reset";
7036 break;
7037 case MPI_EVENT_EXT_BUS_RESET:
7038 ds = "External Bus Reset";
7039 break;
7040 case MPI_EVENT_RESCAN:
7041 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007042 break;
7043 case MPI_EVENT_LINK_STATUS_CHANGE:
7044 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
7045 ds = "Link Status(FAILURE) Change";
7046 else
7047 ds = "Link Status(ACTIVE) Change";
7048 break;
7049 case MPI_EVENT_LOOP_STATE_CHANGE:
7050 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
7051 ds = "Loop State(LIP) Change";
7052 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Kashyap, Desai2f187862009-05-29 16:52:37 +05307053 ds = "Loop State(LPE) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007054 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05307055 ds = "Loop State(LPB) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007056 break;
7057 case MPI_EVENT_LOGOUT:
7058 ds = "Logout";
7059 break;
7060 case MPI_EVENT_EVENT_CHANGE:
7061 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06007062 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007063 else
Eric Moore4f766dc2006-07-11 17:24:07 -06007064 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007065 break;
7066 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007067 {
7068 u8 ReasonCode = (u8)(evData0 >> 16);
7069 switch (ReasonCode) {
7070 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
7071 ds = "Integrated Raid: Volume Created";
7072 break;
7073 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
7074 ds = "Integrated Raid: Volume Deleted";
7075 break;
7076 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
7077 ds = "Integrated Raid: Volume Settings Changed";
7078 break;
7079 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
7080 ds = "Integrated Raid: Volume Status Changed";
7081 break;
7082 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
7083 ds = "Integrated Raid: Volume Physdisk Changed";
7084 break;
7085 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
7086 ds = "Integrated Raid: Physdisk Created";
7087 break;
7088 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
7089 ds = "Integrated Raid: Physdisk Deleted";
7090 break;
7091 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
7092 ds = "Integrated Raid: Physdisk Settings Changed";
7093 break;
7094 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
7095 ds = "Integrated Raid: Physdisk Status Changed";
7096 break;
7097 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
7098 ds = "Integrated Raid: Domain Validation Needed";
7099 break;
7100 case MPI_EVENT_RAID_RC_SMART_DATA :
7101 ds = "Integrated Raid; Smart Data";
7102 break;
7103 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
7104 ds = "Integrated Raid: Replace Action Started";
7105 break;
7106 default:
7107 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007108 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007109 }
7110 break;
7111 }
7112 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
7113 ds = "SCSI Device Status Change";
7114 break;
7115 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
7116 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007117 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007118 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007119 u8 ReasonCode = (u8)(evData0 >> 16);
7120 switch (ReasonCode) {
7121 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007122 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007123 "SAS Device Status Change: Added: "
7124 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007125 break;
7126 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06007127 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007128 "SAS Device Status Change: Deleted: "
7129 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007130 break;
7131 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06007132 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007133 "SAS Device Status Change: SMART Data: "
7134 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007135 break;
7136 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007137 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007138 "SAS Device Status Change: No Persistancy: "
7139 "id=%d channel=%d", id, channel);
7140 break;
7141 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
7142 snprintf(evStr, EVENT_DESCR_STR_SZ,
7143 "SAS Device Status Change: Unsupported Device "
7144 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007145 break;
7146 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
7147 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007148 "SAS Device Status Change: Internal Device "
7149 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007150 break;
7151 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
7152 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007153 "SAS Device Status Change: Internal Task "
7154 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007155 break;
7156 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
7157 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007158 "SAS Device Status Change: Internal Abort "
7159 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007160 break;
7161 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
7162 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007163 "SAS Device Status Change: Internal Clear "
7164 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007165 break;
7166 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
7167 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007168 "SAS Device Status Change: Internal Query "
7169 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007170 break;
7171 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007172 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007173 "SAS Device Status Change: Unknown: "
7174 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06007175 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007176 }
7177 break;
7178 }
7179 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
7180 ds = "Bus Timer Expired";
7181 break;
7182 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07007183 {
7184 u16 curr_depth = (u16)(evData0 >> 16);
7185 u8 channel = (u8)(evData0 >> 8);
7186 u8 id = (u8)(evData0);
7187
7188 snprintf(evStr, EVENT_DESCR_STR_SZ,
7189 "Queue Full: channel=%d id=%d depth=%d",
7190 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007191 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07007192 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007193 case MPI_EVENT_SAS_SES:
7194 ds = "SAS SES Event";
7195 break;
7196 case MPI_EVENT_PERSISTENT_TABLE_FULL:
7197 ds = "Persistent Table Full";
7198 break;
7199 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07007200 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007201 u8 LinkRates = (u8)(evData0 >> 8);
7202 u8 PhyNumber = (u8)(evData0);
7203 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
7204 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
7205 switch (LinkRates) {
7206 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06007207 snprintf(evStr, EVENT_DESCR_STR_SZ,
7208 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007209 " Rate Unknown",PhyNumber);
7210 break;
7211 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06007212 snprintf(evStr, EVENT_DESCR_STR_SZ,
7213 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007214 " Phy Disabled",PhyNumber);
7215 break;
7216 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06007217 snprintf(evStr, EVENT_DESCR_STR_SZ,
7218 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007219 " Failed Speed Nego",PhyNumber);
7220 break;
7221 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06007222 snprintf(evStr, EVENT_DESCR_STR_SZ,
7223 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007224 " Sata OOB Completed",PhyNumber);
7225 break;
7226 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06007227 snprintf(evStr, EVENT_DESCR_STR_SZ,
7228 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007229 " Rate 1.5 Gbps",PhyNumber);
7230 break;
7231 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
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 3.0 Gpbs",PhyNumber);
7235 break;
7236 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007237 snprintf(evStr, EVENT_DESCR_STR_SZ,
7238 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007239 break;
7240 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007241 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007242 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007243 case MPI_EVENT_SAS_DISCOVERY_ERROR:
7244 ds = "SAS Discovery Error";
7245 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007246 case MPI_EVENT_IR_RESYNC_UPDATE:
7247 {
7248 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06007249 snprintf(evStr, EVENT_DESCR_STR_SZ,
7250 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07007251 break;
7252 }
7253 case MPI_EVENT_IR2:
7254 {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307255 u8 id = (u8)(evData0);
7256 u8 channel = (u8)(evData0 >> 8);
7257 u8 phys_num = (u8)(evData0 >> 24);
Moore, Eric3a892be2006-03-14 09:14:03 -07007258 u8 ReasonCode = (u8)(evData0 >> 16);
Kashyap, Desai2f187862009-05-29 16:52:37 +05307259
Moore, Eric3a892be2006-03-14 09:14:03 -07007260 switch (ReasonCode) {
7261 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307262 snprintf(evStr, EVENT_DESCR_STR_SZ,
7263 "IR2: LD State Changed: "
7264 "id=%d channel=%d phys_num=%d",
7265 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007266 break;
7267 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307268 snprintf(evStr, EVENT_DESCR_STR_SZ,
7269 "IR2: PD State Changed "
7270 "id=%d channel=%d phys_num=%d",
7271 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007272 break;
7273 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307274 snprintf(evStr, EVENT_DESCR_STR_SZ,
7275 "IR2: Bad Block Table Full: "
7276 "id=%d channel=%d phys_num=%d",
7277 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007278 break;
7279 case MPI_EVENT_IR2_RC_PD_INSERTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307280 snprintf(evStr, EVENT_DESCR_STR_SZ,
7281 "IR2: PD Inserted: "
7282 "id=%d channel=%d phys_num=%d",
7283 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007284 break;
7285 case MPI_EVENT_IR2_RC_PD_REMOVED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307286 snprintf(evStr, EVENT_DESCR_STR_SZ,
7287 "IR2: PD Removed: "
7288 "id=%d channel=%d phys_num=%d",
7289 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007290 break;
7291 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307292 snprintf(evStr, EVENT_DESCR_STR_SZ,
7293 "IR2: Foreign CFG Detected: "
7294 "id=%d channel=%d phys_num=%d",
7295 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007296 break;
7297 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307298 snprintf(evStr, EVENT_DESCR_STR_SZ,
7299 "IR2: Rebuild Medium Error: "
7300 "id=%d channel=%d phys_num=%d",
7301 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007302 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05307303 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
7304 snprintf(evStr, EVENT_DESCR_STR_SZ,
7305 "IR2: Dual Port Added: "
7306 "id=%d channel=%d phys_num=%d",
7307 id, channel, phys_num);
7308 break;
7309 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
7310 snprintf(evStr, EVENT_DESCR_STR_SZ,
7311 "IR2: Dual Port Removed: "
7312 "id=%d channel=%d phys_num=%d",
7313 id, channel, phys_num);
7314 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007315 default:
7316 ds = "IR2";
7317 break;
7318 }
7319 break;
7320 }
7321 case MPI_EVENT_SAS_DISCOVERY:
7322 {
7323 if (evData0)
7324 ds = "SAS Discovery: Start";
7325 else
7326 ds = "SAS Discovery: Stop";
7327 break;
7328 }
7329 case MPI_EVENT_LOG_ENTRY_ADDED:
7330 ds = "SAS Log Entry Added";
7331 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007332
Eric Moorec6c727a2007-01-29 09:44:54 -07007333 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
7334 {
7335 u8 phy_num = (u8)(evData0);
7336 u8 port_num = (u8)(evData0 >> 8);
7337 u8 port_width = (u8)(evData0 >> 16);
7338 u8 primative = (u8)(evData0 >> 24);
7339 snprintf(evStr, EVENT_DESCR_STR_SZ,
7340 "SAS Broadcase Primative: phy=%d port=%d "
7341 "width=%d primative=0x%02x",
7342 phy_num, port_num, port_width, primative);
7343 break;
7344 }
7345
7346 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7347 {
7348 u8 reason = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007349
Kashyap, Desai2f187862009-05-29 16:52:37 +05307350 switch (reason) {
7351 case MPI_EVENT_SAS_INIT_RC_ADDED:
7352 ds = "SAS Initiator Status Change: Added";
7353 break;
7354 case MPI_EVENT_SAS_INIT_RC_REMOVED:
7355 ds = "SAS Initiator Status Change: Deleted";
7356 break;
7357 default:
7358 ds = "SAS Initiator Status Change";
7359 break;
7360 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007361 break;
7362 }
7363
7364 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7365 {
7366 u8 max_init = (u8)(evData0);
7367 u8 current_init = (u8)(evData0 >> 8);
7368
7369 snprintf(evStr, EVENT_DESCR_STR_SZ,
7370 "SAS Initiator Device Table Overflow: max initiators=%02d "
7371 "current initators=%02d",
7372 max_init, current_init);
7373 break;
7374 }
7375 case MPI_EVENT_SAS_SMP_ERROR:
7376 {
7377 u8 status = (u8)(evData0);
7378 u8 port_num = (u8)(evData0 >> 8);
7379 u8 result = (u8)(evData0 >> 16);
7380
7381 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7382 snprintf(evStr, EVENT_DESCR_STR_SZ,
7383 "SAS SMP Error: port=%d result=0x%02x",
7384 port_num, result);
7385 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7386 snprintf(evStr, EVENT_DESCR_STR_SZ,
7387 "SAS SMP Error: port=%d : CRC Error",
7388 port_num);
7389 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7390 snprintf(evStr, EVENT_DESCR_STR_SZ,
7391 "SAS SMP Error: port=%d : Timeout",
7392 port_num);
7393 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7394 snprintf(evStr, EVENT_DESCR_STR_SZ,
7395 "SAS SMP Error: port=%d : No Destination",
7396 port_num);
7397 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7398 snprintf(evStr, EVENT_DESCR_STR_SZ,
7399 "SAS SMP Error: port=%d : Bad Destination",
7400 port_num);
7401 else
7402 snprintf(evStr, EVENT_DESCR_STR_SZ,
7403 "SAS SMP Error: port=%d : status=0x%02x",
7404 port_num, status);
7405 break;
7406 }
7407
Kashyap, Desai2f187862009-05-29 16:52:37 +05307408 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
7409 {
7410 u8 reason = (u8)(evData0);
7411
7412 switch (reason) {
7413 case MPI_EVENT_SAS_EXP_RC_ADDED:
7414 ds = "Expander Status Change: Added";
7415 break;
7416 case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
7417 ds = "Expander Status Change: Deleted";
7418 break;
7419 default:
7420 ds = "Expander Status Change";
7421 break;
7422 }
7423 break;
7424 }
7425
Linus Torvalds1da177e2005-04-16 15:20:36 -07007426 /*
7427 * MPT base "custom" events may be added here...
7428 */
7429 default:
7430 ds = "Unknown";
7431 break;
7432 }
Eric Moore509e5e52006-04-26 13:22:37 -06007433 if (ds)
7434 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007435
Kashyap, Desai2f187862009-05-29 16:52:37 +05307436
7437 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7438 "MPT event:(%02Xh) : %s\n",
7439 ioc->name, event, evStr));
7440
7441 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
7442 ": Event data:\n"));
7443 for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
7444 devtverboseprintk(ioc, printk(" %08x",
7445 le32_to_cpu(pEventReply->Data[ii])));
7446 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
7447}
7448#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007449/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007450/**
7451 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007452 * @ioc: Pointer to MPT_ADAPTER structure
7453 * @pEventReply: Pointer to EventNotification reply frame
7454 * @evHandlers: Pointer to integer, number of event handlers
7455 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007456 * Routes a received EventNotificationReply to all currently registered
7457 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007458 * Returns sum of event handlers return values.
7459 */
7460static int
7461ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7462{
7463 u16 evDataLen;
7464 u32 evData0 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007465 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307466 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007467 int r = 0;
7468 int handlers = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007469 u8 event;
7470
7471 /*
7472 * Do platform normalization of values
7473 */
7474 event = le32_to_cpu(pEventReply->Event) & 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007475 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7476 if (evDataLen) {
7477 evData0 = le32_to_cpu(pEventReply->Data[0]);
7478 }
7479
Prakash, Sathya436ace72007-07-24 15:42:08 +05307480#ifdef CONFIG_FUSION_LOGGING
Kashyap, Desai2f187862009-05-29 16:52:37 +05307481 if (evDataLen)
7482 mpt_display_event_info(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007483#endif
7484
7485 /*
7486 * Do general / base driver event processing
7487 */
7488 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007489 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7490 if (evDataLen) {
7491 u8 evState = evData0 & 0xFF;
7492
7493 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7494
7495 /* Update EventState field in cached IocFacts */
7496 if (ioc->facts.Function) {
7497 ioc->facts.EventState = evState;
7498 }
7499 }
7500 break;
Moore, Ericece50912006-01-16 18:53:19 -07007501 case MPI_EVENT_INTEGRATED_RAID:
7502 mptbase_raid_process_event_data(ioc,
7503 (MpiEventDataRaid_t *)pEventReply->Data);
7504 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007505 default:
7506 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007507 }
7508
7509 /*
7510 * Should this event be logged? Events are written sequentially.
7511 * When buffer is full, start again at the top.
7512 */
7513 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7514 int idx;
7515
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007516 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007517
7518 ioc->events[idx].event = event;
7519 ioc->events[idx].eventContext = ioc->eventContext;
7520
7521 for (ii = 0; ii < 2; ii++) {
7522 if (ii < evDataLen)
7523 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7524 else
7525 ioc->events[idx].data[ii] = 0;
7526 }
7527
7528 ioc->eventContext++;
7529 }
7530
7531
7532 /*
7533 * Call each currently registered protocol event handler.
7534 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007535 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307536 if (MptEvHandlers[cb_idx]) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307537 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7538 "Routing Event to event handler #%d\n",
7539 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307540 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007541 handlers++;
7542 }
7543 }
7544 /* FIXME? Examine results here? */
7545
7546 /*
7547 * If needed, send (a single) EventAck.
7548 */
7549 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307550 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007551 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007552 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307553 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007554 ioc->name, ii));
7555 }
7556 }
7557
7558 *evHandlers = handlers;
7559 return r;
7560}
7561
7562/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007563/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007564 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7565 * @ioc: Pointer to MPT_ADAPTER structure
7566 * @log_info: U32 LogInfo reply word from the IOC
7567 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007568 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007569 */
7570static void
7571mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7572{
Eric Moore7c431e52007-06-13 16:34:36 -06007573 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007574
Eric Moore7c431e52007-06-13 16:34:36 -06007575 switch (log_info & 0xFF000000) {
7576 case MPI_IOCLOGINFO_FC_INIT_BASE:
7577 desc = "FCP Initiator";
7578 break;
7579 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7580 desc = "FCP Target";
7581 break;
7582 case MPI_IOCLOGINFO_FC_LAN_BASE:
7583 desc = "LAN";
7584 break;
7585 case MPI_IOCLOGINFO_FC_MSG_BASE:
7586 desc = "MPI Message Layer";
7587 break;
7588 case MPI_IOCLOGINFO_FC_LINK_BASE:
7589 desc = "FC Link";
7590 break;
7591 case MPI_IOCLOGINFO_FC_CTX_BASE:
7592 desc = "Context Manager";
7593 break;
7594 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7595 desc = "Invalid Field Offset";
7596 break;
7597 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7598 desc = "State Change Info";
7599 break;
7600 }
7601
7602 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7603 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007604}
7605
7606/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007607/**
Moore, Eric335a9412006-01-17 17:06:23 -07007608 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007609 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007610 * @log_info: U32 LogInfo word from the IOC
7611 *
7612 * Refer to lsi/sp_log.h.
7613 */
7614static void
Moore, Eric335a9412006-01-17 17:06:23 -07007615mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007616{
7617 u32 info = log_info & 0x00FF0000;
7618 char *desc = "unknown";
7619
7620 switch (info) {
7621 case 0x00010000:
7622 desc = "bug! MID not found";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007623 break;
7624
7625 case 0x00020000:
7626 desc = "Parity Error";
7627 break;
7628
7629 case 0x00030000:
7630 desc = "ASYNC Outbound Overrun";
7631 break;
7632
7633 case 0x00040000:
7634 desc = "SYNC Offset Error";
7635 break;
7636
7637 case 0x00050000:
7638 desc = "BM Change";
7639 break;
7640
7641 case 0x00060000:
7642 desc = "Msg In Overflow";
7643 break;
7644
7645 case 0x00070000:
7646 desc = "DMA Error";
7647 break;
7648
7649 case 0x00080000:
7650 desc = "Outbound DMA Overrun";
7651 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007652
Linus Torvalds1da177e2005-04-16 15:20:36 -07007653 case 0x00090000:
7654 desc = "Task Management";
7655 break;
7656
7657 case 0x000A0000:
7658 desc = "Device Problem";
7659 break;
7660
7661 case 0x000B0000:
7662 desc = "Invalid Phase Change";
7663 break;
7664
7665 case 0x000C0000:
7666 desc = "Untagged Table Size";
7667 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007668
Linus Torvalds1da177e2005-04-16 15:20:36 -07007669 }
7670
7671 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7672}
7673
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007674/* strings for sas loginfo */
7675 static char *originator_str[] = {
7676 "IOP", /* 00h */
7677 "PL", /* 01h */
7678 "IR" /* 02h */
7679 };
7680 static char *iop_code_str[] = {
7681 NULL, /* 00h */
7682 "Invalid SAS Address", /* 01h */
7683 NULL, /* 02h */
7684 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007685 "Diag Message Error", /* 04h */
7686 "Task Terminated", /* 05h */
7687 "Enclosure Management", /* 06h */
7688 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007689 };
7690 static char *pl_code_str[] = {
7691 NULL, /* 00h */
7692 "Open Failure", /* 01h */
7693 "Invalid Scatter Gather List", /* 02h */
7694 "Wrong Relative Offset or Frame Length", /* 03h */
7695 "Frame Transfer Error", /* 04h */
7696 "Transmit Frame Connected Low", /* 05h */
7697 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7698 "SATA Read Log Receive Data Error", /* 07h */
7699 "SATA NCQ Fail All Commands After Error", /* 08h */
7700 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7701 "Receive Frame Invalid Message", /* 0Ah */
7702 "Receive Context Message Valid Error", /* 0Bh */
7703 "Receive Frame Current Frame Error", /* 0Ch */
7704 "SATA Link Down", /* 0Dh */
7705 "Discovery SATA Init W IOS", /* 0Eh */
7706 "Config Invalid Page", /* 0Fh */
7707 "Discovery SATA Init Timeout", /* 10h */
7708 "Reset", /* 11h */
7709 "Abort", /* 12h */
7710 "IO Not Yet Executed", /* 13h */
7711 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007712 "Persistent Reservation Out Not Affiliation "
7713 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007714 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007715 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007716 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007717 NULL, /* 19h */
7718 NULL, /* 1Ah */
7719 NULL, /* 1Bh */
7720 NULL, /* 1Ch */
7721 NULL, /* 1Dh */
7722 NULL, /* 1Eh */
7723 NULL, /* 1Fh */
7724 "Enclosure Management" /* 20h */
7725 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007726 static char *ir_code_str[] = {
7727 "Raid Action Error", /* 00h */
7728 NULL, /* 00h */
7729 NULL, /* 01h */
7730 NULL, /* 02h */
7731 NULL, /* 03h */
7732 NULL, /* 04h */
7733 NULL, /* 05h */
7734 NULL, /* 06h */
7735 NULL /* 07h */
7736 };
7737 static char *raid_sub_code_str[] = {
7738 NULL, /* 00h */
7739 "Volume Creation Failed: Data Passed too "
7740 "Large", /* 01h */
7741 "Volume Creation Failed: Duplicate Volumes "
7742 "Attempted", /* 02h */
7743 "Volume Creation Failed: Max Number "
7744 "Supported Volumes Exceeded", /* 03h */
7745 "Volume Creation Failed: DMA Error", /* 04h */
7746 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7747 "Volume Creation Failed: Error Reading "
7748 "MFG Page 4", /* 06h */
7749 "Volume Creation Failed: Creating Internal "
7750 "Structures", /* 07h */
7751 NULL, /* 08h */
7752 NULL, /* 09h */
7753 NULL, /* 0Ah */
7754 NULL, /* 0Bh */
7755 NULL, /* 0Ch */
7756 NULL, /* 0Dh */
7757 NULL, /* 0Eh */
7758 NULL, /* 0Fh */
7759 "Activation failed: Already Active Volume", /* 10h */
7760 "Activation failed: Unsupported Volume Type", /* 11h */
7761 "Activation failed: Too Many Active Volumes", /* 12h */
7762 "Activation failed: Volume ID in Use", /* 13h */
7763 "Activation failed: Reported Failure", /* 14h */
7764 "Activation failed: Importing a Volume", /* 15h */
7765 NULL, /* 16h */
7766 NULL, /* 17h */
7767 NULL, /* 18h */
7768 NULL, /* 19h */
7769 NULL, /* 1Ah */
7770 NULL, /* 1Bh */
7771 NULL, /* 1Ch */
7772 NULL, /* 1Dh */
7773 NULL, /* 1Eh */
7774 NULL, /* 1Fh */
7775 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7776 "Phys Disk failed: Data Passed too Large", /* 21h */
7777 "Phys Disk failed: DMA Error", /* 22h */
7778 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7779 "Phys Disk failed: Creating Phys Disk Config "
7780 "Page", /* 24h */
7781 NULL, /* 25h */
7782 NULL, /* 26h */
7783 NULL, /* 27h */
7784 NULL, /* 28h */
7785 NULL, /* 29h */
7786 NULL, /* 2Ah */
7787 NULL, /* 2Bh */
7788 NULL, /* 2Ch */
7789 NULL, /* 2Dh */
7790 NULL, /* 2Eh */
7791 NULL, /* 2Fh */
7792 "Compatibility Error: IR Disabled", /* 30h */
7793 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7794 "Compatibility Error: Device not Direct Access "
7795 "Device ", /* 32h */
7796 "Compatibility Error: Removable Device Found", /* 33h */
7797 "Compatibility Error: Device SCSI Version not "
7798 "2 or Higher", /* 34h */
7799 "Compatibility Error: SATA Device, 48 BIT LBA "
7800 "not Supported", /* 35h */
7801 "Compatibility Error: Device doesn't have "
7802 "512 Byte Block Sizes", /* 36h */
7803 "Compatibility Error: Volume Type Check Failed", /* 37h */
7804 "Compatibility Error: Volume Type is "
7805 "Unsupported by FW", /* 38h */
7806 "Compatibility Error: Disk Drive too Small for "
7807 "use in Volume", /* 39h */
7808 "Compatibility Error: Phys Disk for Create "
7809 "Volume not Found", /* 3Ah */
7810 "Compatibility Error: Too Many or too Few "
7811 "Disks for Volume Type", /* 3Bh */
7812 "Compatibility Error: Disk stripe Sizes "
7813 "Must be 64KB", /* 3Ch */
7814 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7815 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007816
7817/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007818/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007819 * mpt_sas_log_info - Log information returned from SAS IOC.
7820 * @ioc: Pointer to MPT_ADAPTER structure
7821 * @log_info: U32 LogInfo reply word from the IOC
7822 *
7823 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007824 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007825static void
7826mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7827{
7828union loginfo_type {
7829 u32 loginfo;
7830 struct {
7831 u32 subcode:16;
7832 u32 code:8;
7833 u32 originator:4;
7834 u32 bus_type:4;
7835 }dw;
7836};
7837 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007838 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007839 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007840 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007841
7842 sas_loginfo.loginfo = log_info;
7843 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007844 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007845 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007846
7847 originator_desc = originator_str[sas_loginfo.dw.originator];
7848
7849 switch (sas_loginfo.dw.originator) {
7850
7851 case 0: /* IOP */
7852 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007853 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007854 code_desc = iop_code_str[sas_loginfo.dw.code];
7855 break;
7856 case 1: /* PL */
7857 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007858 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007859 code_desc = pl_code_str[sas_loginfo.dw.code];
7860 break;
7861 case 2: /* IR */
7862 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007863 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007864 break;
7865 code_desc = ir_code_str[sas_loginfo.dw.code];
7866 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007867 ARRAY_SIZE(raid_sub_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007868 break;
7869 if (sas_loginfo.dw.code == 0)
7870 sub_code_desc =
7871 raid_sub_code_str[sas_loginfo.dw.subcode];
7872 break;
7873 default:
7874 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007875 }
7876
Eric Moorec6c727a2007-01-29 09:44:54 -07007877 if (sub_code_desc != NULL)
7878 printk(MYIOC_s_INFO_FMT
7879 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7880 " SubCode={%s}\n",
7881 ioc->name, log_info, originator_desc, code_desc,
7882 sub_code_desc);
7883 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007884 printk(MYIOC_s_INFO_FMT
7885 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7886 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007887 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007888 sas_loginfo.dw.subcode);
7889 else
7890 printk(MYIOC_s_INFO_FMT
7891 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7892 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007893 ioc->name, log_info, originator_desc,
7894 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007895}
7896
Linus Torvalds1da177e2005-04-16 15:20:36 -07007897/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007898/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007899 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7900 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007901 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007902 * @mf: Pointer to MPT request frame
7903 *
7904 * Refer to lsi/mpi.h.
7905 **/
7906static void
7907mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7908{
7909 Config_t *pReq = (Config_t *)mf;
7910 char extend_desc[EVENT_DESCR_STR_SZ];
7911 char *desc = NULL;
7912 u32 form;
7913 u8 page_type;
7914
7915 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7916 page_type = pReq->ExtPageType;
7917 else
7918 page_type = pReq->Header.PageType;
7919
7920 /*
7921 * ignore invalid page messages for GET_NEXT_HANDLE
7922 */
7923 form = le32_to_cpu(pReq->PageAddress);
7924 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7925 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7926 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7927 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7928 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7929 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7930 return;
7931 }
7932 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7933 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7934 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7935 return;
7936 }
7937
7938 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7939 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7940 page_type, pReq->Header.PageNumber, pReq->Action, form);
7941
7942 switch (ioc_status) {
7943
7944 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7945 desc = "Config Page Invalid Action";
7946 break;
7947
7948 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7949 desc = "Config Page Invalid Type";
7950 break;
7951
7952 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7953 desc = "Config Page Invalid Page";
7954 break;
7955
7956 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7957 desc = "Config Page Invalid Data";
7958 break;
7959
7960 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7961 desc = "Config Page No Defaults";
7962 break;
7963
7964 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7965 desc = "Config Page Can't Commit";
7966 break;
7967 }
7968
7969 if (!desc)
7970 return;
7971
Eric Moore29dd3602007-09-14 18:46:51 -06007972 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7973 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007974}
7975
7976/**
7977 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007978 * @ioc: Pointer to MPT_ADAPTER structure
7979 * @ioc_status: U32 IOCStatus word from IOC
7980 * @mf: Pointer to MPT request frame
7981 *
7982 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007983 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007984static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007985mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007986{
7987 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007988 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007989
7990 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007991
7992/****************************************************************************/
7993/* Common IOCStatus values for all replies */
7994/****************************************************************************/
7995
Linus Torvalds1da177e2005-04-16 15:20:36 -07007996 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7997 desc = "Invalid Function";
7998 break;
7999
8000 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
8001 desc = "Busy";
8002 break;
8003
8004 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
8005 desc = "Invalid SGL";
8006 break;
8007
8008 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
8009 desc = "Internal Error";
8010 break;
8011
8012 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
8013 desc = "Reserved";
8014 break;
8015
8016 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
8017 desc = "Insufficient Resources";
8018 break;
8019
8020 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
8021 desc = "Invalid Field";
8022 break;
8023
8024 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
8025 desc = "Invalid State";
8026 break;
8027
Eric Moorec6c727a2007-01-29 09:44:54 -07008028/****************************************************************************/
8029/* Config IOCStatus values */
8030/****************************************************************************/
8031
Linus Torvalds1da177e2005-04-16 15:20:36 -07008032 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8033 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8034 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8035 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8036 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8037 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008038 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008039 break;
8040
Eric Moorec6c727a2007-01-29 09:44:54 -07008041/****************************************************************************/
8042/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
8043/* */
8044/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
8045/* */
8046/****************************************************************************/
8047
Linus Torvalds1da177e2005-04-16 15:20:36 -07008048 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008049 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008050 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
8051 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
8052 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
8053 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008054 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008055 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008056 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008057 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008058 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008059 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07008060 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008061 break;
8062
Eric Moorec6c727a2007-01-29 09:44:54 -07008063/****************************************************************************/
8064/* SCSI Target values */
8065/****************************************************************************/
8066
8067 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
8068 desc = "Target: Priority IO";
8069 break;
8070
8071 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
8072 desc = "Target: Invalid Port";
8073 break;
8074
8075 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
8076 desc = "Target Invalid IO Index:";
8077 break;
8078
8079 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
8080 desc = "Target: Aborted";
8081 break;
8082
8083 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
8084 desc = "Target: No Conn Retryable";
8085 break;
8086
8087 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
8088 desc = "Target: No Connection";
8089 break;
8090
8091 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
8092 desc = "Target: Transfer Count Mismatch";
8093 break;
8094
8095 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
8096 desc = "Target: STS Data not Sent";
8097 break;
8098
8099 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
8100 desc = "Target: Data Offset Error";
8101 break;
8102
8103 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
8104 desc = "Target: Too Much Write Data";
8105 break;
8106
8107 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
8108 desc = "Target: IU Too Short";
8109 break;
8110
8111 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
8112 desc = "Target: ACK NAK Timeout";
8113 break;
8114
8115 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
8116 desc = "Target: Nak Received";
8117 break;
8118
8119/****************************************************************************/
8120/* Fibre Channel Direct Access values */
8121/****************************************************************************/
8122
8123 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
8124 desc = "FC: Aborted";
8125 break;
8126
8127 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
8128 desc = "FC: RX ID Invalid";
8129 break;
8130
8131 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
8132 desc = "FC: DID Invalid";
8133 break;
8134
8135 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
8136 desc = "FC: Node Logged Out";
8137 break;
8138
8139 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
8140 desc = "FC: Exchange Canceled";
8141 break;
8142
8143/****************************************************************************/
8144/* LAN values */
8145/****************************************************************************/
8146
8147 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
8148 desc = "LAN: Device not Found";
8149 break;
8150
8151 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
8152 desc = "LAN: Device Failure";
8153 break;
8154
8155 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
8156 desc = "LAN: Transmit Error";
8157 break;
8158
8159 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
8160 desc = "LAN: Transmit Aborted";
8161 break;
8162
8163 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
8164 desc = "LAN: Receive Error";
8165 break;
8166
8167 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
8168 desc = "LAN: Receive Aborted";
8169 break;
8170
8171 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
8172 desc = "LAN: Partial Packet";
8173 break;
8174
8175 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
8176 desc = "LAN: Canceled";
8177 break;
8178
8179/****************************************************************************/
8180/* Serial Attached SCSI values */
8181/****************************************************************************/
8182
8183 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
8184 desc = "SAS: SMP Request Failed";
8185 break;
8186
8187 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
8188 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07008189 break;
8190
8191 default:
8192 desc = "Others";
8193 break;
8194 }
Eric Moorec6c727a2007-01-29 09:44:54 -07008195
8196 if (!desc)
8197 return;
8198
Eric Moore29dd3602007-09-14 18:46:51 -06008199 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
8200 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008201}
8202
8203/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008204EXPORT_SYMBOL(mpt_attach);
8205EXPORT_SYMBOL(mpt_detach);
8206#ifdef CONFIG_PM
8207EXPORT_SYMBOL(mpt_resume);
8208EXPORT_SYMBOL(mpt_suspend);
8209#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07008210EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008211EXPORT_SYMBOL(mpt_register);
8212EXPORT_SYMBOL(mpt_deregister);
8213EXPORT_SYMBOL(mpt_event_register);
8214EXPORT_SYMBOL(mpt_event_deregister);
8215EXPORT_SYMBOL(mpt_reset_register);
8216EXPORT_SYMBOL(mpt_reset_deregister);
8217EXPORT_SYMBOL(mpt_device_driver_register);
8218EXPORT_SYMBOL(mpt_device_driver_deregister);
8219EXPORT_SYMBOL(mpt_get_msg_frame);
8220EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05308221EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008222EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008223EXPORT_SYMBOL(mpt_send_handshake_request);
8224EXPORT_SYMBOL(mpt_verify_adapter);
8225EXPORT_SYMBOL(mpt_GetIocState);
8226EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008227EXPORT_SYMBOL(mpt_HardResetHandler);
8228EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008229EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008230EXPORT_SYMBOL(mpt_alloc_fw_memory);
8231EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02008232EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07008233EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008234
Linus Torvalds1da177e2005-04-16 15:20:36 -07008235/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008236/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008237 * fusion_init - Fusion MPT base driver initialization routine.
8238 *
8239 * Returns 0 for success, non-zero for failure.
8240 */
8241static int __init
8242fusion_init(void)
8243{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308244 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008245
8246 show_mptmod_ver(my_NAME, my_VERSION);
8247 printk(KERN_INFO COPYRIGHT "\n");
8248
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308249 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
8250 MptCallbacks[cb_idx] = NULL;
8251 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
8252 MptEvHandlers[cb_idx] = NULL;
8253 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008254 }
8255
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008256 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07008257 * EventNotification handling.
8258 */
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05308259 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008260
8261 /* Register for hard reset handling callbacks.
8262 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05308263 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008264
8265#ifdef CONFIG_PROC_FS
8266 (void) procmpt_create();
8267#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008268 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008269}
8270
8271/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008272/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008273 * fusion_exit - Perform driver unload cleanup.
8274 *
8275 * This routine frees all resources associated with each MPT adapter
8276 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
8277 */
8278static void __exit
8279fusion_exit(void)
8280{
8281
Linus Torvalds1da177e2005-04-16 15:20:36 -07008282 mpt_reset_deregister(mpt_base_index);
8283
8284#ifdef CONFIG_PROC_FS
8285 procmpt_destroy();
8286#endif
8287}
8288
Linus Torvalds1da177e2005-04-16 15:20:36 -07008289module_init(fusion_init);
8290module_exit(fusion_exit);