blob: 9f6b315624aaf2ba3907d783367f77fc71fb6005 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptbase.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * This is the Fusion MPT base driver which supports multiple
4 * (SCSI + LAN) specialized protocol drivers.
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05305 * For use with LSI PCI chip/adapter(s)
6 * running LSI Fusion MPT (Message Passing Technology) firmware.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Prakash, Sathyacddc0ab2008-05-21 00:56:41 +05308 * Copyright (c) 1999-2008 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06009 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13/*
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; version 2 of the License.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 NO WARRANTY
24 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
25 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
26 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
27 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
28 solely responsible for determining the appropriateness of using and
29 distributing the Program and assumes all risks associated with its
30 exercise of rights under this Agreement, including but not limited to
31 the risks and costs of program errors, damage to or loss of data,
32 programs or equipment, and unavailability or interruption of operations.
33
34 DISCLAIMER OF LIABILITY
35 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
38 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
40 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
41 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
42
43 You should have received a copy of the GNU General Public License
44 along with this program; if not, write to the Free Software
45 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46*/
47/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/kernel.h>
50#include <linux/module.h>
51#include <linux/errno.h>
52#include <linux/init.h>
53#include <linux/slab.h>
54#include <linux/types.h>
55#include <linux/pci.h>
56#include <linux/kdev_t.h>
57#include <linux/blkdev.h>
58#include <linux/delay.h>
59#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040060#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <asm/io.h>
62#ifdef CONFIG_MTRR
63#include <asm/mtrr.h>
64#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#include "mptbase.h"
Eric Moore7c431e52007-06-13 16:34:36 -060067#include "lsi/mpi_log_fc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT base driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptbase"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/*
80 * cmd line parameters
81 */
Kashyap, Desaie3829682009-01-08 14:27:16 +053082
83static int mpt_msi_enable_spi;
84module_param(mpt_msi_enable_spi, int, 0);
85MODULE_PARM_DESC(mpt_msi_enable_spi, " Enable MSI Support for SPI \
86 controllers (default=0)");
87
88static int mpt_msi_enable_fc;
89module_param(mpt_msi_enable_fc, int, 0);
90MODULE_PARM_DESC(mpt_msi_enable_fc, " Enable MSI Support for FC \
91 controllers (default=0)");
92
93static int mpt_msi_enable_sas;
Yinghai Lu5ce78682009-02-18 11:25:32 -080094module_param(mpt_msi_enable_sas, int, 0);
Kashyap, Desaie3829682009-01-08 14:27:16 +053095MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS \
Yinghai Lu5ce78682009-02-18 11:25:32 -080096 controllers (default=0)");
Kashyap, Desaie3829682009-01-08 14:27:16 +053097
Christoph Hellwig4ddce142006-01-17 13:44:29 +000098
Eric Moore793955f2007-01-29 09:42:20 -070099static int mpt_channel_mapping;
100module_param(mpt_channel_mapping, int, 0);
101MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
102
Prakash, Sathya436ace72007-07-24 15:42:08 +0530103static int mpt_debug_level;
James Bottomleydb47c2d2007-07-28 13:40:21 -0400104static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
105module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
106 &mpt_debug_level, 0600);
Kashyap, Desaie3829682009-01-08 14:27:16 +0530107MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h \
108 - (default=0)");
109
Kashyap, Desai2f4c7822009-01-06 15:03:37 +0530110int mpt_fwfault_debug;
111EXPORT_SYMBOL(mpt_fwfault_debug);
112module_param_call(mpt_fwfault_debug, param_set_int, param_get_int,
113 &mpt_fwfault_debug, 0600);
114MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault"
115 " and halt Firmware on fault - (default=0)");
116
117
Prakash, Sathya436ace72007-07-24 15:42:08 +0530118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119#ifdef MFCNT
120static int mfcounter = 0;
121#define PRINT_MF_COUNT 20000
122#endif
123
124/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
125/*
126 * Public data...
127 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
Adrian Bunk15424922008-04-22 00:31:51 +0300129static struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
131#define WHOINIT_UNKNOWN 0xAA
132
133/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
134/*
135 * Private data...
136 */
137 /* Adapter link list */
138LIST_HEAD(ioc_list);
139 /* Callback lookup table */
140static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
141 /* Protocol driver class lookup table */
142static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
143 /* Event handler lookup table */
144static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
145 /* Reset handler lookup table */
146static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
147static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
148
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530150/*
151 * Driver Callback Index's
152 */
153static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
154static u8 last_drv_idx;
155
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
157/*
158 * Forward protos...
159 */
David Howells7d12e782006-10-05 14:55:46 +0100160static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530161static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
162 MPT_FRAME_HDR *reply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
164 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
165 int sleepFlag);
166static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
167static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
168static void mpt_adapter_disable(MPT_ADAPTER *ioc);
169static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
170
171static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
172static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
174static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
175static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
176static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
177static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200178static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
180static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
181static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
182static int PrimeIocFifos(MPT_ADAPTER *ioc);
183static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
184static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
185static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
186static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200188int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
190static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
191static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
192static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530193static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Kashyap, Desaifd761752009-05-29 16:39:06 +0530194static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch,
195 int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200197static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
198static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
200#ifdef CONFIG_PROC_FS
201static int procmpt_summary_read(char *buf, char **start, off_t offset,
202 int request, int *eof, void *data);
203static int procmpt_version_read(char *buf, char **start, off_t offset,
204 int request, int *eof, void *data);
205static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
206 int request, int *eof, void *data);
207#endif
208static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
209
Kashyap, Desaifd761752009-05-29 16:39:06 +0530210static int ProcessEventNotification(MPT_ADAPTER *ioc,
211 EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700212static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700214static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600215static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700216static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700217static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
219/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220static int __init fusion_init (void);
221static void __exit fusion_exit (void);
222
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223#define CHIPREG_READ32(addr) readl_relaxed(addr)
224#define CHIPREG_READ32_dmasync(addr) readl(addr)
225#define CHIPREG_WRITE32(addr,val) writel(val, addr)
226#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
227#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
228
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600229static void
230pci_disable_io_access(struct pci_dev *pdev)
231{
232 u16 command_reg;
233
234 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
235 command_reg &= ~1;
236 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
237}
238
239static void
240pci_enable_io_access(struct pci_dev *pdev)
241{
242 u16 command_reg;
243
244 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
245 command_reg |= 1;
246 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
247}
248
James Bottomleydb47c2d2007-07-28 13:40:21 -0400249static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
250{
251 int ret = param_set_int(val, kp);
252 MPT_ADAPTER *ioc;
253
254 if (ret)
255 return ret;
256
257 list_for_each_entry(ioc, &ioc_list, list)
258 ioc->debug_level = mpt_debug_level;
259 return 0;
260}
261
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530262/**
263 * mpt_get_cb_idx - obtain cb_idx for registered driver
264 * @dclass: class driver enum
265 *
266 * Returns cb_idx, or zero means it wasn't found
267 **/
268static u8
269mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
270{
271 u8 cb_idx;
272
273 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
274 if (MptDriverClass[cb_idx] == dclass)
275 return cb_idx;
276 return 0;
277}
278
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530279/**
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530280 * mpt_is_discovery_complete - determine if discovery has completed
281 * @ioc: per adatper instance
282 *
283 * Returns 1 when discovery completed, else zero.
284 */
285static int
286mpt_is_discovery_complete(MPT_ADAPTER *ioc)
287{
288 ConfigExtendedPageHeader_t hdr;
289 CONFIGPARMS cfg;
290 SasIOUnitPage0_t *buffer;
291 dma_addr_t dma_handle;
292 int rc = 0;
293
294 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
295 memset(&cfg, 0, sizeof(CONFIGPARMS));
296 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
297 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
298 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
299 cfg.cfghdr.ehdr = &hdr;
300 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
301
302 if ((mpt_config(ioc, &cfg)))
303 goto out;
304 if (!hdr.ExtPageLength)
305 goto out;
306
307 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
308 &dma_handle);
309 if (!buffer)
310 goto out;
311
312 cfg.physAddr = dma_handle;
313 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
314
315 if ((mpt_config(ioc, &cfg)))
316 goto out_free_consistent;
317
318 if (!(buffer->PhyData[0].PortFlags &
319 MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS))
320 rc = 1;
321
322 out_free_consistent:
323 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
324 buffer, dma_handle);
325 out:
326 return rc;
327}
328
329/**
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530330 * mpt_fault_reset_work - work performed on workq after ioc fault
331 * @work: input argument, used to derive ioc
332 *
333**/
334static void
335mpt_fault_reset_work(struct work_struct *work)
336{
337 MPT_ADAPTER *ioc =
338 container_of(work, MPT_ADAPTER, fault_reset_work.work);
339 u32 ioc_raw_state;
340 int rc;
341 unsigned long flags;
342
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530343 if (ioc->ioc_reset_in_progress || !ioc->active)
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530344 goto out;
345
346 ioc_raw_state = mpt_GetIocState(ioc, 0);
347 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
348 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700349 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530350 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700351 ioc->name, __func__);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530352 rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
353 printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700354 __func__, (rc == 0) ? "success" : "failed");
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530355 ioc_raw_state = mpt_GetIocState(ioc, 0);
356 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
357 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
358 "reset (%04xh)\n", ioc->name, ioc_raw_state &
359 MPI_DOORBELL_DATA_MASK);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530360 } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) {
361 if ((mpt_is_discovery_complete(ioc))) {
362 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing "
363 "discovery_quiesce_io flag\n", ioc->name));
364 ioc->sas_discovery_quiesce_io = 0;
365 }
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530366 }
367
368 out:
369 /*
370 * Take turns polling alternate controller
371 */
372 if (ioc->alt_ioc)
373 ioc = ioc->alt_ioc;
374
375 /* rearm the timer */
Kashyap, Desai2f187862009-05-29 16:52:37 +0530376 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530377 if (ioc->reset_work_q)
378 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
379 msecs_to_jiffies(MPT_POLLING_INTERVAL));
Kashyap, Desai2f187862009-05-29 16:52:37 +0530380 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530381}
382
383
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600384/*
385 * Process turbo (context) reply...
386 */
387static void
388mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
389{
390 MPT_FRAME_HDR *mf = NULL;
391 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530392 u16 req_idx = 0;
393 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600394
Prakash, Sathya436ace72007-07-24 15:42:08 +0530395 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600396 ioc->name, pa));
397
398 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
399 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
400 req_idx = pa & 0x0000FFFF;
401 cb_idx = (pa & 0x00FF0000) >> 16;
402 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
403 break;
404 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530405 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600406 /*
407 * Blind set of mf to NULL here was fatal
408 * after lan_reply says "freeme"
409 * Fix sort of combined with an optimization here;
410 * added explicit check for case where lan_reply
411 * was just returning 1 and doing nothing else.
412 * For this case skip the callback, but set up
413 * proper mf value first here:-)
414 */
415 if ((pa & 0x58000000) == 0x58000000) {
416 req_idx = pa & 0x0000FFFF;
417 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
418 mpt_free_msg_frame(ioc, mf);
419 mb();
420 return;
421 break;
422 }
423 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
424 break;
425 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530426 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600427 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
428 break;
429 default:
430 cb_idx = 0;
431 BUG();
432 }
433
434 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530435 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600436 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600437 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700438 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600439 goto out;
440 }
441
442 if (MptCallbacks[cb_idx](ioc, mf, mr))
443 mpt_free_msg_frame(ioc, mf);
444 out:
445 mb();
446}
447
448static void
449mpt_reply(MPT_ADAPTER *ioc, u32 pa)
450{
451 MPT_FRAME_HDR *mf;
452 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530453 u16 req_idx;
454 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600455 int freeme;
456
457 u32 reply_dma_low;
458 u16 ioc_stat;
459
460 /* non-TURBO reply! Hmmm, something may be up...
461 * Newest turbo reply mechanism; get address
462 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
463 */
464
465 /* Map DMA address of reply header to cpu address.
466 * pa is 32 bits - but the dma address may be 32 or 64 bits
467 * get offset based only only the low addresses
468 */
469
470 reply_dma_low = (pa <<= 1);
471 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
472 (reply_dma_low - ioc->reply_frames_low_dma));
473
474 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
475 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
476 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
477
Prakash, Sathya436ace72007-07-24 15:42:08 +0530478 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600479 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600480 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600481
482 /* Check/log IOC log info
483 */
484 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
485 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
486 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
487 if (ioc->bus_type == FC)
488 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700489 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700490 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600491 else if (ioc->bus_type == SAS)
492 mpt_sas_log_info(ioc, log_info);
493 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600494
Eric Moorec6c727a2007-01-29 09:44:54 -0700495 if (ioc_stat & MPI_IOCSTATUS_MASK)
496 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600497
498 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530499 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600500 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600501 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700502 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600503 freeme = 0;
504 goto out;
505 }
506
507 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
508
509 out:
510 /* Flush (non-TURBO) reply with a WRITE! */
511 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
512
513 if (freeme)
514 mpt_free_msg_frame(ioc, mf);
515 mb();
516}
517
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800519/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
521 * @irq: irq number (not used)
522 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 *
524 * This routine is registered via the request_irq() kernel API call,
525 * and handles all interrupts generated from a specific MPT adapter
526 * (also referred to as a IO Controller or IOC).
527 * This routine must clear the interrupt from the adapter and does
528 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200529 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 *
531 * This routine handles register-level access of the adapter but
532 * dispatches (calls) a protocol-specific callback routine to handle
533 * the protocol-specific details of the MPT request completion.
534 */
535static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100536mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600538 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600539 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
540
541 if (pa == 0xFFFFFFFF)
542 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
544 /*
545 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600547 do {
548 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600549 mpt_reply(ioc, pa);
550 else
551 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600552 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
553 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
555 return IRQ_HANDLED;
556}
557
558/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800559/**
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530560 * mptbase_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 * @ioc: Pointer to MPT_ADAPTER structure
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530562 * @req: Pointer to original MPT request frame
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
564 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800565 * MPT base driver's callback routine; all base driver
566 * "internal" request/reply processing is routed here.
567 * Currently used for EventNotification and EventAck handling.
568 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200569 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 * should be freed, or 0 if it shouldn't.
571 */
572static int
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530573mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530575 EventNotificationReply_t *pEventReply;
576 u8 event;
577 int evHandlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 int freereq = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530580 switch (reply->u.hdr.Function) {
581 case MPI_FUNCTION_EVENT_NOTIFICATION:
582 pEventReply = (EventNotificationReply_t *)reply;
583 evHandlers = 0;
584 ProcessEventNotification(ioc, pEventReply, &evHandlers);
585 event = le32_to_cpu(pEventReply->Event) & 0xFF;
586 if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 freereq = 0;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530588 if (event != MPI_EVENT_EVENT_CHANGE)
589 break;
590 case MPI_FUNCTION_CONFIG:
591 case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
592 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
593 if (reply) {
594 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
595 memcpy(ioc->mptbase_cmds.reply, reply,
596 min(MPT_DEFAULT_FRAME_SIZE,
597 4 * reply->u.reply.MsgLength));
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200598 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530599 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
600 ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
601 complete(&ioc->mptbase_cmds.done);
602 } else
603 freereq = 0;
604 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF)
605 freereq = 1;
606 break;
607 case MPI_FUNCTION_EVENT_ACK:
608 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
609 "EventAck reply received\n", ioc->name));
610 break;
611 default:
612 printk(MYIOC_s_ERR_FMT
613 "Unexpected msg function (=%02Xh) reply received!\n",
614 ioc->name, reply->u.hdr.Function);
615 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 }
617
618 /*
619 * Conditionally tell caller to free the original
620 * EventNotification/EventAck/unexpected request frame!
621 */
622 return freereq;
623}
624
625/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
626/**
627 * mpt_register - Register protocol-specific main callback handler.
628 * @cbfunc: callback function pointer
629 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
630 *
631 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800632 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 * protocol-specific driver must do this before it will be able to
634 * use any IOC resources, such as obtaining request frames.
635 *
636 * NOTES: The SCSI protocol driver currently calls this routine thrice
637 * in order to register separate callbacks; one for "normal" SCSI IO;
638 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
639 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530640 * Returns u8 valued "handle" in the range (and S.O.D. order)
641 * {N,...,7,6,5,...,1} if successful.
642 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
643 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530645u8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
647{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530648 u8 cb_idx;
649 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
651 /*
652 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
653 * (slot/handle 0 is reserved!)
654 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530655 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
656 if (MptCallbacks[cb_idx] == NULL) {
657 MptCallbacks[cb_idx] = cbfunc;
658 MptDriverClass[cb_idx] = dclass;
659 MptEvHandlers[cb_idx] = NULL;
660 last_drv_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 break;
662 }
663 }
664
665 return last_drv_idx;
666}
667
668/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
669/**
670 * mpt_deregister - Deregister a protocol drivers resources.
671 * @cb_idx: previously registered callback handle
672 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800673 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 * module is unloaded.
675 */
676void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530677mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600679 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 MptCallbacks[cb_idx] = NULL;
681 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
682 MptEvHandlers[cb_idx] = NULL;
683
684 last_drv_idx++;
685 }
686}
687
688/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
689/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800690 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 * @cb_idx: previously registered (via mpt_register) callback handle
692 * @ev_cbfunc: callback function
693 *
694 * This routine can be called by one or more protocol-specific drivers
695 * if/when they choose to be notified of MPT events.
696 *
697 * Returns 0 for success.
698 */
699int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530700mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600702 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 return -1;
704
705 MptEvHandlers[cb_idx] = ev_cbfunc;
706 return 0;
707}
708
709/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
710/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800711 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 * @cb_idx: previously registered callback handle
713 *
714 * Each protocol-specific driver should call this routine
715 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800716 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 */
718void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530719mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600721 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 return;
723
724 MptEvHandlers[cb_idx] = NULL;
725}
726
727/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
728/**
729 * mpt_reset_register - Register protocol-specific IOC reset handler.
730 * @cb_idx: previously registered (via mpt_register) callback handle
731 * @reset_func: reset function
732 *
733 * This routine can be called by one or more protocol-specific drivers
734 * if/when they choose to be notified of IOC resets.
735 *
736 * Returns 0 for success.
737 */
738int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530739mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530741 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 return -1;
743
744 MptResetHandlers[cb_idx] = reset_func;
745 return 0;
746}
747
748/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
749/**
750 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
751 * @cb_idx: previously registered callback handle
752 *
753 * Each protocol-specific driver should call this routine
754 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800755 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 */
757void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530758mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530760 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 return;
762
763 MptResetHandlers[cb_idx] = NULL;
764}
765
766/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
767/**
768 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800769 * @dd_cbfunc: driver callbacks struct
770 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 */
772int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530773mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774{
775 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600776 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777
Eric Moore8d6d83e2007-09-14 18:47:40 -0600778 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400779 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
781 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
782
783 /* call per pci device probe entry point */
784 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600785 id = ioc->pcidev->driver ?
786 ioc->pcidev->driver->id_table : NULL;
787 if (dd_cbfunc->probe)
788 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 }
790
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400791 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792}
793
794/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
795/**
796 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800797 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 */
799void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530800mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801{
802 struct mpt_pci_driver *dd_cbfunc;
803 MPT_ADAPTER *ioc;
804
Eric Moore8d6d83e2007-09-14 18:47:40 -0600805 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 return;
807
808 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
809
810 list_for_each_entry(ioc, &ioc_list, list) {
811 if (dd_cbfunc->remove)
812 dd_cbfunc->remove(ioc->pcidev);
813 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200814
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 MptDeviceDriverHandlers[cb_idx] = NULL;
816}
817
818
819/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
820/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800821 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530822 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 * @ioc: Pointer to MPT adapter structure
824 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800825 * Obtain an MPT request frame from the pool (of 1024) that are
826 * allocated per MPT adapter.
827 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 * Returns pointer to a MPT request frame or %NULL if none are available
829 * or IOC is not active.
830 */
831MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530832mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833{
834 MPT_FRAME_HDR *mf;
835 unsigned long flags;
836 u16 req_idx; /* Request index */
837
838 /* validate handle and ioc identifier */
839
840#ifdef MFCNT
841 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600842 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
843 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844#endif
845
846 /* If interrupts are not attached, do not return a request frame */
847 if (!ioc->active)
848 return NULL;
849
850 spin_lock_irqsave(&ioc->FreeQlock, flags);
851 if (!list_empty(&ioc->FreeQ)) {
852 int req_offset;
853
854 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
855 u.frame.linkage.list);
856 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200857 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530858 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
860 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500861 req_idx = req_offset / ioc->req_sz;
862 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600864 /* Default, will be changed if necessary in SG generation */
865 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866#ifdef MFCNT
867 ioc->mfcnt++;
868#endif
869 }
870 else
871 mf = NULL;
872 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
873
874#ifdef MFCNT
875 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600876 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
877 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
878 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 mfcounter++;
880 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600881 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
882 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883#endif
884
Eric Moore29dd3602007-09-14 18:46:51 -0600885 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
886 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 return mf;
888}
889
890/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
891/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800892 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530893 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 * @ioc: Pointer to MPT adapter structure
895 * @mf: Pointer to MPT request frame
896 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800897 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 * specific MPT adapter.
899 */
900void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530901mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902{
903 u32 mf_dma_addr;
904 int req_offset;
905 u16 req_idx; /* Request index */
906
907 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530908 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
910 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500911 req_idx = req_offset / ioc->req_sz;
912 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
914
Prakash, Sathya436ace72007-07-24 15:42:08 +0530915 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200917 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600918 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
919 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
920 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
922}
923
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530924/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800925 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530926 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530927 * @ioc: Pointer to MPT adapter structure
928 * @mf: Pointer to MPT request frame
929 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800930 * Send a protocol-specific MPT request frame to an IOC using
931 * hi-priority request queue.
932 *
933 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530934 * specific MPT adapter.
935 **/
936void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530937mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530938{
939 u32 mf_dma_addr;
940 int req_offset;
941 u16 req_idx; /* Request index */
942
943 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530944 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530945 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
946 req_idx = req_offset / ioc->req_sz;
947 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
948 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
949
950 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
951
952 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
953 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
954 ioc->name, mf_dma_addr, req_idx));
955 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
956}
957
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
959/**
960 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 * @ioc: Pointer to MPT adapter structure
962 * @mf: Pointer to MPT request frame
963 *
964 * This routine places a MPT request frame back on the MPT adapter's
965 * FreeQ.
966 */
967void
968mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
969{
970 unsigned long flags;
971
972 /* Put Request back on FreeQ! */
973 spin_lock_irqsave(&ioc->FreeQlock, flags);
Kashyap, Desai2f187862009-05-29 16:52:37 +0530974 if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf)
975 goto out;
976 /* signature to know if this mf is freed */
977 mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
979#ifdef MFCNT
980 ioc->mfcnt--;
981#endif
Kashyap, Desai2f187862009-05-29 16:52:37 +0530982 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
984}
985
986/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
987/**
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530988 * mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 * @pAddr: virtual address for SGE
990 * @flagslength: SGE flags and data transfer length
991 * @dma_addr: Physical address
992 *
993 * This routine places a MPT request frame back on the MPT adapter's
994 * FreeQ.
995 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530996static void
997mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998{
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530999 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
1000 pSge->FlagsLength = cpu_to_le32(flagslength);
1001 pSge->Address = cpu_to_le32(dma_addr);
1002}
1003
1004/**
1005 * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
1006 * @pAddr: virtual address for SGE
1007 * @flagslength: SGE flags and data transfer length
1008 * @dma_addr: Physical address
1009 *
1010 * This routine places a MPT request frame back on the MPT adapter's
1011 * FreeQ.
1012 **/
1013static void
1014mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1015{
1016 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1017 pSge->Address.Low = cpu_to_le32
1018 (lower_32_bits((unsigned long)(dma_addr)));
1019 pSge->Address.High = cpu_to_le32
1020 (upper_32_bits((unsigned long)dma_addr));
1021 pSge->FlagsLength = cpu_to_le32
1022 ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1023}
1024
1025/**
1026 * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr
1027 * (1078 workaround).
1028 * @pAddr: virtual address for SGE
1029 * @flagslength: SGE flags and data transfer length
1030 * @dma_addr: Physical address
1031 *
1032 * This routine places a MPT request frame back on the MPT adapter's
1033 * FreeQ.
1034 **/
1035static void
1036mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1037{
1038 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1039 u32 tmp;
1040
1041 pSge->Address.Low = cpu_to_le32
1042 (lower_32_bits((unsigned long)(dma_addr)));
1043 tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
1044
1045 /*
1046 * 1078 errata workaround for the 36GB limitation
1047 */
1048 if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {
1049 flagslength |=
1050 MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
1051 tmp |= (1<<31);
1052 if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
1053 printk(KERN_DEBUG "1078 P0M2 addressing for "
1054 "addr = 0x%llx len = %d\n",
1055 (unsigned long long)dma_addr,
1056 MPI_SGE_LENGTH(flagslength));
1057 }
1058
1059 pSge->Address.High = cpu_to_le32(tmp);
1060 pSge->FlagsLength = cpu_to_le32(
1061 (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1062}
1063
1064/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1065/**
1066 * mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
1067 * @pAddr: virtual address for SGE
1068 * @next: nextChainOffset value (u32's)
1069 * @length: length of next SGL segment
1070 * @dma_addr: Physical address
1071 *
1072 */
1073static void
1074mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1075{
1076 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
1077 pChain->Length = cpu_to_le16(length);
1078 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
1079 pChain->NextChainOffset = next;
1080 pChain->Address = cpu_to_le32(dma_addr);
1081}
1082
1083/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1084/**
1085 * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
1086 * @pAddr: virtual address for SGE
1087 * @next: nextChainOffset value (u32's)
1088 * @length: length of next SGL segment
1089 * @dma_addr: Physical address
1090 *
1091 */
1092static void
1093mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1094{
1095 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 u32 tmp = dma_addr & 0xFFFFFFFF;
1097
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301098 pChain->Length = cpu_to_le16(length);
1099 pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
1100 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301102 pChain->NextChainOffset = next;
1103
1104 pChain->Address.Low = cpu_to_le32(tmp);
1105 tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
1106 pChain->Address.High = cpu_to_le32(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107}
1108
1109/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1110/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001111 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301112 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 * @ioc: Pointer to MPT adapter structure
1114 * @reqBytes: Size of the request in bytes
1115 * @req: Pointer to MPT request frame
1116 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1117 *
1118 * This routine is used exclusively to send MptScsiTaskMgmt
1119 * requests since they are required to be sent via doorbell handshake.
1120 *
1121 * NOTE: It is the callers responsibility to byte-swap fields in the
1122 * request which are greater than 1 byte in size.
1123 *
1124 * Returns 0 for success, non-zero for failure.
1125 */
1126int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301127mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128{
Eric Moorecd2c6192007-01-29 09:47:47 -07001129 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 u8 *req_as_bytes;
1131 int ii;
1132
1133 /* State is known to be good upon entering
1134 * this function so issue the bus reset
1135 * request.
1136 */
1137
1138 /*
1139 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1140 * setting cb_idx/req_idx. But ONLY if this request
1141 * is in proper (pre-alloc'd) request buffer range...
1142 */
1143 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1144 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1145 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1146 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301147 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 }
1149
1150 /* Make sure there are no doorbells */
1151 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001152
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1154 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1155 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1156
1157 /* Wait for IOC doorbell int */
1158 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1159 return ii;
1160 }
1161
1162 /* Read doorbell and check for active bit */
1163 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1164 return -5;
1165
Eric Moore29dd3602007-09-14 18:46:51 -06001166 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001167 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
1169 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1170
1171 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1172 return -2;
1173 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001174
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 /* Send request via doorbell handshake */
1176 req_as_bytes = (u8 *) req;
1177 for (ii = 0; ii < reqBytes/4; ii++) {
1178 u32 word;
1179
1180 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1181 (req_as_bytes[(ii*4) + 1] << 8) |
1182 (req_as_bytes[(ii*4) + 2] << 16) |
1183 (req_as_bytes[(ii*4) + 3] << 24));
1184 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1185 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1186 r = -3;
1187 break;
1188 }
1189 }
1190
1191 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1192 r = 0;
1193 else
1194 r = -4;
1195
1196 /* Make sure there are no doorbells */
1197 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001198
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 return r;
1200}
1201
1202/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1203/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001204 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001205 * @ioc: Pointer to MPT adapter structure
1206 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001207 * @sleepFlag: Specifies whether the process can sleep
1208 *
1209 * Provides mechanism for the host driver to control the IOC's
1210 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001211 *
1212 * Access Control Value - bits[15:12]
1213 * 0h Reserved
1214 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1215 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1216 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1217 *
1218 * Returns 0 for success, non-zero for failure.
1219 */
1220
1221static int
1222mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1223{
1224 int r = 0;
1225
1226 /* return if in use */
1227 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1228 & MPI_DOORBELL_ACTIVE)
1229 return -1;
1230
1231 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1232
1233 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1234 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1235 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1236 (access_control_value<<12)));
1237
1238 /* Wait for IOC to clear Doorbell Status bit */
1239 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1240 return -2;
1241 }else
1242 return 0;
1243}
1244
1245/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1246/**
1247 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001248 * @ioc: Pointer to pointer to IOC adapter
1249 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001250 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001251 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001252 * Returns 0 for success, non-zero for failure.
1253 */
1254static int
1255mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1256{
1257 char *psge;
1258 int flags_length;
1259 u32 host_page_buffer_sz=0;
1260
1261 if(!ioc->HostPageBuffer) {
1262
1263 host_page_buffer_sz =
1264 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1265
1266 if(!host_page_buffer_sz)
1267 return 0; /* fw doesn't need any host buffers */
1268
1269 /* spin till we get enough memory */
1270 while(host_page_buffer_sz > 0) {
1271
1272 if((ioc->HostPageBuffer = pci_alloc_consistent(
1273 ioc->pcidev,
1274 host_page_buffer_sz,
1275 &ioc->HostPageBuffer_dma)) != NULL) {
1276
Prakash, Sathya436ace72007-07-24 15:42:08 +05301277 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001278 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001279 ioc->name, ioc->HostPageBuffer,
1280 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001281 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001282 ioc->alloc_total += host_page_buffer_sz;
1283 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1284 break;
1285 }
1286
1287 host_page_buffer_sz -= (4*1024);
1288 }
1289 }
1290
1291 if(!ioc->HostPageBuffer) {
1292 printk(MYIOC_s_ERR_FMT
1293 "Failed to alloc memory for host_page_buffer!\n",
1294 ioc->name);
1295 return -999;
1296 }
1297
1298 psge = (char *)&ioc_init->HostPageBufferSGE;
1299 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1300 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1301 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1302 MPI_SGE_FLAGS_HOST_TO_IOC |
1303 MPI_SGE_FLAGS_END_OF_BUFFER;
1304 if (sizeof(dma_addr_t) == sizeof(u64)) {
1305 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1306 }
1307 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1308 flags_length |= ioc->HostPageBuffer_sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301309 ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001310 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1311
1312return 0;
1313}
1314
1315/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1316/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001317 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 * @iocid: IOC unique identifier (integer)
1319 * @iocpp: Pointer to pointer to IOC adapter
1320 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001321 * Given a unique IOC identifier, set pointer to the associated MPT
1322 * adapter structure.
1323 *
1324 * Returns iocid and sets iocpp if iocid is found.
1325 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 */
1327int
1328mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1329{
1330 MPT_ADAPTER *ioc;
1331
1332 list_for_each_entry(ioc,&ioc_list,list) {
1333 if (ioc->id == iocid) {
1334 *iocpp =ioc;
1335 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001336 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001338
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 *iocpp = NULL;
1340 return -1;
1341}
1342
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301343/**
1344 * mpt_get_product_name - returns product string
1345 * @vendor: pci vendor id
1346 * @device: pci device id
1347 * @revision: pci revision id
1348 * @prod_name: string returned
1349 *
1350 * Returns product string displayed when driver loads,
1351 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1352 *
1353 **/
1354static void
1355mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1356{
1357 char *product_str = NULL;
1358
1359 if (vendor == PCI_VENDOR_ID_BROCADE) {
1360 switch (device)
1361 {
1362 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1363 switch (revision)
1364 {
1365 case 0x00:
1366 product_str = "BRE040 A0";
1367 break;
1368 case 0x01:
1369 product_str = "BRE040 A1";
1370 break;
1371 default:
1372 product_str = "BRE040";
1373 break;
1374 }
1375 break;
1376 }
1377 goto out;
1378 }
1379
1380 switch (device)
1381 {
1382 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1383 product_str = "LSIFC909 B1";
1384 break;
1385 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1386 product_str = "LSIFC919 B0";
1387 break;
1388 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1389 product_str = "LSIFC929 B0";
1390 break;
1391 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1392 if (revision < 0x80)
1393 product_str = "LSIFC919X A0";
1394 else
1395 product_str = "LSIFC919XL A1";
1396 break;
1397 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1398 if (revision < 0x80)
1399 product_str = "LSIFC929X A0";
1400 else
1401 product_str = "LSIFC929XL A1";
1402 break;
1403 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1404 product_str = "LSIFC939X A1";
1405 break;
1406 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1407 product_str = "LSIFC949X A1";
1408 break;
1409 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1410 switch (revision)
1411 {
1412 case 0x00:
1413 product_str = "LSIFC949E A0";
1414 break;
1415 case 0x01:
1416 product_str = "LSIFC949E A1";
1417 break;
1418 default:
1419 product_str = "LSIFC949E";
1420 break;
1421 }
1422 break;
1423 case MPI_MANUFACTPAGE_DEVID_53C1030:
1424 switch (revision)
1425 {
1426 case 0x00:
1427 product_str = "LSI53C1030 A0";
1428 break;
1429 case 0x01:
1430 product_str = "LSI53C1030 B0";
1431 break;
1432 case 0x03:
1433 product_str = "LSI53C1030 B1";
1434 break;
1435 case 0x07:
1436 product_str = "LSI53C1030 B2";
1437 break;
1438 case 0x08:
1439 product_str = "LSI53C1030 C0";
1440 break;
1441 case 0x80:
1442 product_str = "LSI53C1030T A0";
1443 break;
1444 case 0x83:
1445 product_str = "LSI53C1030T A2";
1446 break;
1447 case 0x87:
1448 product_str = "LSI53C1030T A3";
1449 break;
1450 case 0xc1:
1451 product_str = "LSI53C1020A A1";
1452 break;
1453 default:
1454 product_str = "LSI53C1030";
1455 break;
1456 }
1457 break;
1458 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1459 switch (revision)
1460 {
1461 case 0x03:
1462 product_str = "LSI53C1035 A2";
1463 break;
1464 case 0x04:
1465 product_str = "LSI53C1035 B0";
1466 break;
1467 default:
1468 product_str = "LSI53C1035";
1469 break;
1470 }
1471 break;
1472 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1473 switch (revision)
1474 {
1475 case 0x00:
1476 product_str = "LSISAS1064 A1";
1477 break;
1478 case 0x01:
1479 product_str = "LSISAS1064 A2";
1480 break;
1481 case 0x02:
1482 product_str = "LSISAS1064 A3";
1483 break;
1484 case 0x03:
1485 product_str = "LSISAS1064 A4";
1486 break;
1487 default:
1488 product_str = "LSISAS1064";
1489 break;
1490 }
1491 break;
1492 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1493 switch (revision)
1494 {
1495 case 0x00:
1496 product_str = "LSISAS1064E A0";
1497 break;
1498 case 0x01:
1499 product_str = "LSISAS1064E B0";
1500 break;
1501 case 0x02:
1502 product_str = "LSISAS1064E B1";
1503 break;
1504 case 0x04:
1505 product_str = "LSISAS1064E B2";
1506 break;
1507 case 0x08:
1508 product_str = "LSISAS1064E B3";
1509 break;
1510 default:
1511 product_str = "LSISAS1064E";
1512 break;
1513 }
1514 break;
1515 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1516 switch (revision)
1517 {
1518 case 0x00:
1519 product_str = "LSISAS1068 A0";
1520 break;
1521 case 0x01:
1522 product_str = "LSISAS1068 B0";
1523 break;
1524 case 0x02:
1525 product_str = "LSISAS1068 B1";
1526 break;
1527 default:
1528 product_str = "LSISAS1068";
1529 break;
1530 }
1531 break;
1532 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1533 switch (revision)
1534 {
1535 case 0x00:
1536 product_str = "LSISAS1068E A0";
1537 break;
1538 case 0x01:
1539 product_str = "LSISAS1068E B0";
1540 break;
1541 case 0x02:
1542 product_str = "LSISAS1068E B1";
1543 break;
1544 case 0x04:
1545 product_str = "LSISAS1068E B2";
1546 break;
1547 case 0x08:
1548 product_str = "LSISAS1068E B3";
1549 break;
1550 default:
1551 product_str = "LSISAS1068E";
1552 break;
1553 }
1554 break;
1555 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1556 switch (revision)
1557 {
1558 case 0x00:
1559 product_str = "LSISAS1078 A0";
1560 break;
1561 case 0x01:
1562 product_str = "LSISAS1078 B0";
1563 break;
1564 case 0x02:
1565 product_str = "LSISAS1078 C0";
1566 break;
1567 case 0x03:
1568 product_str = "LSISAS1078 C1";
1569 break;
1570 case 0x04:
1571 product_str = "LSISAS1078 C2";
1572 break;
1573 default:
1574 product_str = "LSISAS1078";
1575 break;
1576 }
1577 break;
1578 }
1579
1580 out:
1581 if (product_str)
1582 sprintf(prod_name, "%s", product_str);
1583}
1584
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301585/**
1586 * mpt_mapresources - map in memory mapped io
1587 * @ioc: Pointer to pointer to IOC adapter
1588 *
1589 **/
1590static int
1591mpt_mapresources(MPT_ADAPTER *ioc)
1592{
1593 u8 __iomem *mem;
1594 int ii;
1595 unsigned long mem_phys;
1596 unsigned long port;
1597 u32 msize;
1598 u32 psize;
1599 u8 revision;
1600 int r = -ENODEV;
1601 struct pci_dev *pdev;
1602
1603 pdev = ioc->pcidev;
1604 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1605 if (pci_enable_device_mem(pdev)) {
1606 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1607 "failed\n", ioc->name);
1608 return r;
1609 }
1610 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1611 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1612 "MEM failed\n", ioc->name);
1613 return r;
1614 }
1615
1616 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1617
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301618 if (sizeof(dma_addr_t) > 4) {
1619 const uint64_t required_mask = dma_get_required_mask
1620 (&pdev->dev);
1621 if (required_mask > DMA_BIT_MASK(32)
1622 && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
1623 && !pci_set_consistent_dma_mask(pdev,
1624 DMA_BIT_MASK(64))) {
1625 ioc->dma_mask = DMA_BIT_MASK(64);
1626 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1627 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1628 ioc->name));
1629 } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1630 && !pci_set_consistent_dma_mask(pdev,
1631 DMA_BIT_MASK(32))) {
1632 ioc->dma_mask = DMA_BIT_MASK(32);
1633 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1634 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1635 ioc->name));
1636 } else {
1637 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1638 ioc->name, pci_name(pdev));
1639 return r;
1640 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301641 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301642 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1643 && !pci_set_consistent_dma_mask(pdev,
1644 DMA_BIT_MASK(32))) {
1645 ioc->dma_mask = DMA_BIT_MASK(32);
1646 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1647 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1648 ioc->name));
1649 } else {
1650 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1651 ioc->name, pci_name(pdev));
1652 return r;
1653 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301654 }
1655
1656 mem_phys = msize = 0;
1657 port = psize = 0;
1658 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1659 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1660 if (psize)
1661 continue;
1662 /* Get I/O space! */
1663 port = pci_resource_start(pdev, ii);
1664 psize = pci_resource_len(pdev, ii);
1665 } else {
1666 if (msize)
1667 continue;
1668 /* Get memmap */
1669 mem_phys = pci_resource_start(pdev, ii);
1670 msize = pci_resource_len(pdev, ii);
1671 }
1672 }
1673 ioc->mem_size = msize;
1674
1675 mem = NULL;
1676 /* Get logical ptr for PciMem0 space */
1677 /*mem = ioremap(mem_phys, msize);*/
1678 mem = ioremap(mem_phys, msize);
1679 if (mem == NULL) {
1680 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1681 " memory!\n", ioc->name);
1682 return -EINVAL;
1683 }
1684 ioc->memmap = mem;
1685 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n",
1686 ioc->name, mem, mem_phys));
1687
1688 ioc->mem_phys = mem_phys;
1689 ioc->chip = (SYSIF_REGS __iomem *)mem;
1690
1691 /* Save Port IO values in case we need to do downloadboot */
1692 ioc->pio_mem_phys = port;
1693 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1694
1695 return 0;
1696}
1697
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001699/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001700 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001702 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 *
1704 * This routine performs all the steps necessary to bring the IOC of
1705 * a MPT adapter to a OPERATIONAL state. This includes registering
1706 * memory regions, registering the interrupt, and allocating request
1707 * and reply memory pools.
1708 *
1709 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1710 * MPT adapter.
1711 *
1712 * Returns 0 for success, non-zero for failure.
1713 *
1714 * TODO: Add support for polled controllers
1715 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001716int
1717mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718{
1719 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301720 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 u8 revision;
1723 u8 pcixcmd;
1724 static int mpt_ids = 0;
1725#ifdef CONFIG_PROC_FS
1726 struct proc_dir_entry *dent, *ent;
1727#endif
1728
Jesper Juhl56876192007-08-10 14:50:51 -07001729 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1730 if (ioc == NULL) {
1731 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1732 return -ENOMEM;
1733 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301734
Eric Moore29dd3602007-09-14 18:46:51 -06001735 ioc->id = mpt_ids++;
1736 sprintf(ioc->name, "ioc%d", ioc->id);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301737 dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Jesper Juhl56876192007-08-10 14:50:51 -07001738
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301739 /*
1740 * set initial debug level
1741 * (refer to mptdebug.h)
1742 *
1743 */
1744 ioc->debug_level = mpt_debug_level;
1745 if (mpt_debug_level)
1746 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301747
Eric Moore29dd3602007-09-14 18:46:51 -06001748 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001749
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301750 ioc->pcidev = pdev;
1751 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001752 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 return r;
1754 }
1755
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301756 /*
1757 * Setting up proper handlers for scatter gather handling
1758 */
1759 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
1760 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
1761 ioc->add_sge = &mpt_add_sge_64bit_1078;
1762 else
1763 ioc->add_sge = &mpt_add_sge_64bit;
1764 ioc->add_chain = &mpt_add_chain_64bit;
1765 ioc->sg_addr_size = 8;
1766 } else {
1767 ioc->add_sge = &mpt_add_sge;
1768 ioc->add_chain = &mpt_add_chain;
1769 ioc->sg_addr_size = 4;
1770 }
1771 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
1772
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 ioc->alloc_total = sizeof(MPT_ADAPTER);
1774 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1775 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001776
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 ioc->pcidev = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301779 spin_lock_init(&ioc->taskmgmt_lock);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05301780 mutex_init(&ioc->internal_cmds.mutex);
1781 init_completion(&ioc->internal_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301782 mutex_init(&ioc->mptbase_cmds.mutex);
1783 init_completion(&ioc->mptbase_cmds.done);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301784 mutex_init(&ioc->taskmgmt_cmds.mutex);
1785 init_completion(&ioc->taskmgmt_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301786
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 /* Initialize the event logging.
1788 */
1789 ioc->eventTypes = 0; /* None */
1790 ioc->eventContext = 0;
1791 ioc->eventLogSize = 0;
1792 ioc->events = NULL;
1793
1794#ifdef MFCNT
1795 ioc->mfcnt = 0;
1796#endif
1797
Kashyap, Desai2f187862009-05-29 16:52:37 +05301798 ioc->sh = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 ioc->cached_fw = NULL;
1800
1801 /* Initilize SCSI Config Data structure
1802 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001803 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804
Michael Reed05e8ec12006-01-13 14:31:54 -06001805 /* Initialize the fc rport list head.
1806 */
1807 INIT_LIST_HEAD(&ioc->fc_rports);
1808
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 /* Find lookup slot. */
1810 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001811
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301812
1813 /* Initialize workqueue */
1814 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301815
Kashyap, Desai2f187862009-05-29 16:52:37 +05301816 snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN,
Kay Sieversaab0de22008-05-02 06:02:41 +02001817 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301818 ioc->reset_work_q =
1819 create_singlethread_workqueue(ioc->reset_work_q_name);
1820 if (!ioc->reset_work_q) {
1821 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1822 ioc->name);
1823 pci_release_selected_regions(pdev, ioc->bars);
1824 kfree(ioc);
1825 return -ENOMEM;
1826 }
1827
Eric Moore29dd3602007-09-14 18:46:51 -06001828 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1829 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301831 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1832 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1833
1834 switch (pdev->device)
1835 {
1836 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1837 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1838 ioc->errata_flag_1064 = 1;
1839 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1840 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1841 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1842 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301844 break;
1845
1846 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 /* 929X Chip Fix. Set Split transactions level
1849 * for PCIX. Set MOST bits to zero.
1850 */
1851 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1852 pcixcmd &= 0x8F;
1853 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1854 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 /* 929XL Chip Fix. Set MMRBC to 0x08.
1856 */
1857 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1858 pcixcmd |= 0x08;
1859 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1860 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301862 break;
1863
1864 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 /* 919X Chip Fix. Set Split transactions level
1866 * for PCIX. Set MOST bits to zero.
1867 */
1868 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1869 pcixcmd &= 0x8F;
1870 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001871 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301872 break;
1873
1874 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 /* 1030 Chip Fix. Disable Split transactions
1876 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1877 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 if (revision < C0_1030) {
1879 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1880 pcixcmd &= 0x8F;
1881 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1882 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301883
1884 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001885 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301886 break;
1887
1888 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1889 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001890 ioc->errata_flag_1064 = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301891 ioc->bus_type = SAS;
1892 break;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301893
1894 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1895 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1896 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001897 ioc->bus_type = SAS;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301898 break;
Eric Moore87cf8982006-06-27 16:09:26 -06001899 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301901
Kashyap, Desaie3829682009-01-08 14:27:16 +05301902 switch (ioc->bus_type) {
1903
1904 case SAS:
1905 ioc->msi_enable = mpt_msi_enable_sas;
1906 break;
1907
1908 case SPI:
1909 ioc->msi_enable = mpt_msi_enable_spi;
1910 break;
1911
1912 case FC:
1913 ioc->msi_enable = mpt_msi_enable_fc;
1914 break;
1915
1916 default:
1917 ioc->msi_enable = 0;
1918 break;
1919 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001920 if (ioc->errata_flag_1064)
1921 pci_disable_io_access(pdev);
1922
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 spin_lock_init(&ioc->FreeQlock);
1924
1925 /* Disable all! */
1926 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1927 ioc->active = 0;
1928 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1929
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301930 /* Set IOC ptr in the pcidev's driver data. */
1931 pci_set_drvdata(ioc->pcidev, ioc);
1932
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 /* Set lookup ptr. */
1934 list_add_tail(&ioc->list, &ioc_list);
1935
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001936 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 */
1938 mpt_detect_bound_ports(ioc, pdev);
1939
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301940 INIT_LIST_HEAD(&ioc->fw_event_list);
1941 spin_lock_init(&ioc->fw_event_lock);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301942 snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301943 ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
1944
James Bottomleyc92f2222006-03-01 09:02:49 -06001945 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1946 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001947 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1948 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001949
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001951 if (ioc->alt_ioc)
1952 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301953 iounmap(ioc->memmap);
1954 if (r != -5)
1955 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301956
1957 destroy_workqueue(ioc->reset_work_q);
1958 ioc->reset_work_q = NULL;
1959
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 kfree(ioc);
1961 pci_set_drvdata(pdev, NULL);
1962 return r;
1963 }
1964
1965 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001966 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301967 if(MptDeviceDriverHandlers[cb_idx] &&
1968 MptDeviceDriverHandlers[cb_idx]->probe) {
1969 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 }
1971 }
1972
1973#ifdef CONFIG_PROC_FS
1974 /*
1975 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1976 */
1977 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1978 if (dent) {
1979 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1980 if (ent) {
1981 ent->read_proc = procmpt_iocinfo_read;
1982 ent->data = ioc;
1983 }
1984 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1985 if (ent) {
1986 ent->read_proc = procmpt_summary_read;
1987 ent->data = ioc;
1988 }
1989 }
1990#endif
1991
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301992 if (!ioc->alt_ioc)
1993 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1994 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1995
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 return 0;
1997}
1998
1999/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002000/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002001 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 */
2004
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002005void
2006mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007{
2008 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2009 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302010 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302011 unsigned long flags;
2012 struct workqueue_struct *wq;
2013
2014 /*
2015 * Stop polling ioc for fault condition
2016 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302017 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302018 wq = ioc->reset_work_q;
2019 ioc->reset_work_q = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302020 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302021 cancel_delayed_work(&ioc->fault_reset_work);
2022 destroy_workqueue(wq);
2023
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05302024 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2025 wq = ioc->fw_event_q;
2026 ioc->fw_event_q = NULL;
2027 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2028 destroy_workqueue(wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029
2030 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2031 remove_proc_entry(pname, NULL);
2032 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2033 remove_proc_entry(pname, NULL);
2034 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2035 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002036
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002038 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302039 if(MptDeviceDriverHandlers[cb_idx] &&
2040 MptDeviceDriverHandlers[cb_idx]->remove) {
2041 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 }
2043 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002044
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 /* Disable interrupts! */
2046 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2047
2048 ioc->active = 0;
2049 synchronize_irq(pdev->irq);
2050
2051 /* Clear any lingering interrupt */
2052 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2053
2054 CHIPREG_READ32(&ioc->chip->IntStatus);
2055
2056 mpt_adapter_dispose(ioc);
2057
2058 pci_set_drvdata(pdev, NULL);
2059}
2060
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061/**************************************************************************
2062 * Power Management
2063 */
2064#ifdef CONFIG_PM
2065/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002066/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002067 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002068 * @pdev: Pointer to pci_dev structure
2069 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002071int
2072mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073{
2074 u32 device_state;
2075 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302077 device_state = pci_choose_state(pdev, state);
2078 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2079 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2080 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081
2082 /* put ioc into READY_STATE */
2083 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2084 printk(MYIOC_s_ERR_FMT
2085 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2086 }
2087
2088 /* disable interrupts */
2089 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2090 ioc->active = 0;
2091
2092 /* Clear any lingering interrupt */
2093 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2094
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302095 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002096 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302097 pci_disable_msi(ioc->pcidev);
2098 ioc->pci_irq = -1;
2099 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302101 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 return 0;
2104}
2105
2106/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002107/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002108 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002109 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002111int
2112mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113{
2114 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2115 u32 device_state = pdev->current_state;
2116 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302117 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002118
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302119 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2120 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2121 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302123 pci_set_power_state(pdev, PCI_D0);
2124 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302126 ioc->pcidev = pdev;
2127 err = mpt_mapresources(ioc);
2128 if (err)
2129 return err;
2130
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302131 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2132 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2133 ioc->add_sge = &mpt_add_sge_64bit_1078;
2134 else
2135 ioc->add_sge = &mpt_add_sge_64bit;
2136 ioc->add_chain = &mpt_add_chain_64bit;
2137 ioc->sg_addr_size = 8;
2138 } else {
2139
2140 ioc->add_sge = &mpt_add_sge;
2141 ioc->add_chain = &mpt_add_chain;
2142 ioc->sg_addr_size = 4;
2143 }
2144 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2145
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302146 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2147 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2148 CHIPREG_READ32(&ioc->chip->Doorbell));
2149
2150 /*
2151 * Errata workaround for SAS pci express:
2152 * Upon returning to the D0 state, the contents of the doorbell will be
2153 * stale data, and this will incorrectly signal to the host driver that
2154 * the firmware is ready to process mpt commands. The workaround is
2155 * to issue a diagnostic reset.
2156 */
2157 if (ioc->bus_type == SAS && (pdev->device ==
2158 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2159 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2160 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2161 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2162 ioc->name);
2163 goto out;
2164 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166
2167 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302168 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2169 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2170 CAN_SLEEP);
2171 if (recovery_state != 0)
2172 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2173 "error:[%x]\n", ioc->name, recovery_state);
2174 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302176 "pci-resume: success\n", ioc->name);
2177 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302179
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180}
2181#endif
2182
James Bottomley4ff42a62006-05-17 18:06:52 -05002183static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302184mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002185{
2186 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2187 ioc->bus_type != SPI) ||
2188 (MptDriverClass[index] == MPTFC_DRIVER &&
2189 ioc->bus_type != FC) ||
2190 (MptDriverClass[index] == MPTSAS_DRIVER &&
2191 ioc->bus_type != SAS))
2192 /* make sure we only call the relevant reset handler
2193 * for the bus */
2194 return 0;
2195 return (MptResetHandlers[index])(ioc, reset_phase);
2196}
2197
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002199/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2201 * @ioc: Pointer to MPT adapter structure
2202 * @reason: Event word / reason
2203 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2204 *
2205 * This routine performs all the steps necessary to bring the IOC
2206 * to a OPERATIONAL state.
2207 *
2208 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2209 * MPT adapter.
2210 *
2211 * Returns:
2212 * 0 for success
2213 * -1 if failed to get board READY
2214 * -2 if READY but IOCFacts Failed
2215 * -3 if READY but PrimeIOCFifos Failed
2216 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302217 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302218 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 */
2220static int
2221mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2222{
2223 int hard_reset_done = 0;
2224 int alt_ioc_ready = 0;
2225 int hard;
2226 int rc=0;
2227 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302228 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 int handlers;
2230 int ret = 0;
2231 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002232 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302233 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
Eric Moore29dd3602007-09-14 18:46:51 -06002235 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2236 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237
2238 /* Disable reply interrupts (also blocks FreeQ) */
2239 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2240 ioc->active = 0;
2241
2242 if (ioc->alt_ioc) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302243 if (ioc->alt_ioc->active ||
2244 reason == MPT_HOSTEVENT_IOC_RECOVER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 reset_alt_ioc_active = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302246 /* Disable alt-IOC's reply interrupts
2247 * (and FreeQ) for a bit
2248 **/
2249 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2250 0xFFFFFFFF);
2251 ioc->alt_ioc->active = 0;
2252 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 }
2254
2255 hard = 1;
2256 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2257 hard = 0;
2258
2259 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2260 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002261 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2262 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263
2264 if (reset_alt_ioc_active && ioc->alt_ioc) {
2265 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002266 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2267 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002268 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 ioc->alt_ioc->active = 1;
2270 }
2271
2272 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302273 printk(MYIOC_s_WARN_FMT
2274 "NOT READY WARNING!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302276 ret = -1;
2277 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 }
2279
2280 /* hard_reset_done = 0 if a soft reset was performed
2281 * and 1 if a hard reset was performed.
2282 */
2283 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2284 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2285 alt_ioc_ready = 1;
2286 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05302287 printk(MYIOC_s_WARN_FMT
2288 ": alt-ioc Not ready WARNING!\n",
2289 ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 }
2291
2292 for (ii=0; ii<5; ii++) {
2293 /* Get IOC facts! Allow 5 retries */
2294 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2295 break;
2296 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002297
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298
2299 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002300 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2301 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 ret = -2;
2303 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2304 MptDisplayIocCapabilities(ioc);
2305 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002306
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 if (alt_ioc_ready) {
2308 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302309 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302310 "Initial Alt IocFacts failed rc=%x\n",
2311 ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 /* Retry - alt IOC was initialized once
2313 */
2314 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2315 }
2316 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302317 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002318 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 alt_ioc_ready = 0;
2320 reset_alt_ioc_active = 0;
2321 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2322 MptDisplayIocCapabilities(ioc->alt_ioc);
2323 }
2324 }
2325
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302326 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2327 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2328 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2329 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2330 IORESOURCE_IO);
2331 if (pci_enable_device(ioc->pcidev))
2332 return -5;
2333 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2334 "mpt"))
2335 return -5;
2336 }
2337
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002338 /*
2339 * Device is reset now. It must have de-asserted the interrupt line
2340 * (if it was asserted) and it should be safe to register for the
2341 * interrupt now.
2342 */
2343 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2344 ioc->pci_irq = -1;
2345 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302346 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002347 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002348 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302349 else
2350 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002351 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002352 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002353 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002354 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Kashyap, Desai2f187862009-05-29 16:52:37 +05302355 "interrupt %d!\n",
2356 ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302357 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002358 pci_disable_msi(ioc->pcidev);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302359 ret = -EBUSY;
2360 goto out;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002361 }
2362 irq_allocated = 1;
2363 ioc->pci_irq = ioc->pcidev->irq;
2364 pci_set_master(ioc->pcidev); /* ?? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302365 pci_set_drvdata(ioc->pcidev, ioc);
2366 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2367 "installed at interrupt %d\n", ioc->name,
2368 ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002369 }
2370 }
2371
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 /* Prime reply & request queues!
2373 * (mucho alloc's) Must be done prior to
2374 * init as upper addresses are needed for init.
2375 * If fails, continue with alt-ioc processing
2376 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302377 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
2378 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2380 ret = -3;
2381
2382 /* May need to check/upload firmware & data here!
2383 * If fails, continue with alt-ioc processing
2384 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302385 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
2386 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2388 ret = -4;
2389// NEW!
2390 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302391 printk(MYIOC_s_WARN_FMT
2392 ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002393 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 alt_ioc_ready = 0;
2395 reset_alt_ioc_active = 0;
2396 }
2397
2398 if (alt_ioc_ready) {
2399 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2400 alt_ioc_ready = 0;
2401 reset_alt_ioc_active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302402 printk(MYIOC_s_WARN_FMT
2403 ": alt-ioc: (%d) init failure WARNING!\n",
2404 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 }
2406 }
2407
2408 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2409 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302410 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002411 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412
2413 /* Controller is not operational, cannot do upload
2414 */
2415 if (ret == 0) {
2416 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002417 if (rc == 0) {
2418 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2419 /*
2420 * Maintain only one pointer to FW memory
2421 * so there will not be two attempt to
2422 * downloadboot onboard dual function
2423 * chips (mpt_adapter_disable,
2424 * mpt_diag_reset)
2425 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302426 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002427 "mpt_upload: alt_%s has cached_fw=%p \n",
2428 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302429 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002430 }
2431 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002432 printk(MYIOC_s_WARN_FMT
2433 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302434 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 }
2437 }
2438 }
2439
Kashyap, Desaifd761752009-05-29 16:39:06 +05302440 /* Enable MPT base driver management of EventNotification
2441 * and EventAck handling.
2442 */
2443 if ((ret == 0) && (!ioc->facts.EventState)) {
2444 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2445 "SendEventNotification\n",
2446 ioc->name));
2447 ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
2448 }
2449
2450 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2451 rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
2452
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 if (ret == 0) {
2454 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002455 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 ioc->active = 1;
2457 }
Kashyap, Desaifd761752009-05-29 16:39:06 +05302458 if (rc == 0) { /* alt ioc */
2459 if (reset_alt_ioc_active && ioc->alt_ioc) {
2460 /* (re)Enable alt-IOC! (reply interrupt) */
2461 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
2462 "reply irq re-enabled\n",
2463 ioc->alt_ioc->name));
2464 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2465 MPI_HIM_DIM);
2466 ioc->alt_ioc->active = 1;
2467 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 }
2469
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002471 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2473 * recursive scenario; GetLanConfigPages times out, timer expired
2474 * routine calls HardResetHandler, which calls into here again,
2475 * and we try GetLanConfigPages again...
2476 */
2477 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002478
2479 /*
2480 * Initalize link list for inactive raid volumes.
2481 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002482 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002483 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2484
Kashyap, Desai2f187862009-05-29 16:52:37 +05302485 switch (ioc->bus_type) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002486
Kashyap, Desai2f187862009-05-29 16:52:37 +05302487 case SAS:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002488 /* clear persistency table */
2489 if(ioc->facts.IOCExceptions &
2490 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2491 ret = mptbase_sas_persist_operation(ioc,
2492 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2493 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002494 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002495 }
2496
2497 /* Find IM volumes
2498 */
2499 mpt_findImVolumes(ioc);
2500
Kashyap, Desai2f187862009-05-29 16:52:37 +05302501 /* Check, and possibly reset, the coalescing value
2502 */
2503 mpt_read_ioc_pg_1(ioc);
2504
2505 break;
2506
2507 case FC:
2508 if ((ioc->pfacts[0].ProtocolFlags &
2509 MPI_PORTFACTS_PROTOCOL_LAN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2511 /*
2512 * Pre-fetch the ports LAN MAC address!
2513 * (LANPage1_t stuff)
2514 */
2515 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302516 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2517 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302518 "LanAddr = %02X:%02X:%02X"
2519 ":%02X:%02X:%02X\n",
2520 ioc->name, a[5], a[4],
2521 a[3], a[2], a[1], a[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302523 break;
2524
2525 case SPI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 /* Get NVRAM and adapter maximums from SPP 0 and 2
2527 */
2528 mpt_GetScsiPortSettings(ioc, 0);
2529
2530 /* Get version and length of SDP 1
2531 */
2532 mpt_readScsiDevicePageHeaders(ioc, 0);
2533
2534 /* Find IM volumes
2535 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002536 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 mpt_findImVolumes(ioc);
2538
2539 /* Check, and possibly reset, the coalescing value
2540 */
2541 mpt_read_ioc_pg_1(ioc);
2542
2543 mpt_read_ioc_pg_4(ioc);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302544
2545 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 }
2547
2548 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302549 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 }
2551
2552 /*
2553 * Call each currently registered protocol IOC reset handler
2554 * with post-reset indication.
2555 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2556 * MptResetHandlers[] registered yet.
2557 */
2558 if (hard_reset_done) {
2559 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302560 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2561 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302562 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002563 "Calling IOC post_reset handler #%d\n",
2564 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302565 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 handlers++;
2567 }
2568
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302569 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302570 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002571 "Calling IOC post_reset handler #%d\n",
2572 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302573 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 handlers++;
2575 }
2576 }
2577 /* FIXME? Examine results here? */
2578 }
2579
Eric Moore0ccdb002006-07-11 17:33:13 -06002580 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002581 if ((ret != 0) && irq_allocated) {
2582 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302583 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002584 pci_disable_msi(ioc->pcidev);
2585 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 return ret;
2587}
2588
2589/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002590/**
2591 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 * @ioc: Pointer to MPT adapter structure
2593 * @pdev: Pointer to (struct pci_dev) structure
2594 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002595 * Search for PCI bus/dev_function which matches
2596 * PCI bus/dev_function (+/-1) for newly discovered 929,
2597 * 929X, 1030 or 1035.
2598 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2600 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2601 */
2602static void
2603mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2604{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002605 struct pci_dev *peer=NULL;
2606 unsigned int slot = PCI_SLOT(pdev->devfn);
2607 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 MPT_ADAPTER *ioc_srch;
2609
Prakash, Sathya436ace72007-07-24 15:42:08 +05302610 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002611 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002612 ioc->name, pci_name(pdev), pdev->bus->number,
2613 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002614
2615 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2616 if (!peer) {
2617 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2618 if (!peer)
2619 return;
2620 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621
2622 list_for_each_entry(ioc_srch, &ioc_list, list) {
2623 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002624 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 /* Paranoia checks */
2626 if (ioc->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302627 printk(MYIOC_s_WARN_FMT
2628 "Oops, already bound (%s <==> %s)!\n",
2629 ioc->name, ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 break;
2631 } else if (ioc_srch->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302632 printk(MYIOC_s_WARN_FMT
2633 "Oops, already bound (%s <==> %s)!\n",
2634 ioc_srch->name, ioc_srch->name,
2635 ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 break;
2637 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302638 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2639 "FOUND! binding %s <==> %s\n",
2640 ioc->name, ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 ioc_srch->alt_ioc = ioc;
2642 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 }
2644 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002645 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646}
2647
2648/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002649/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002651 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 */
2653static void
2654mpt_adapter_disable(MPT_ADAPTER *ioc)
2655{
2656 int sz;
2657 int ret;
2658
2659 if (ioc->cached_fw != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302660 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2661 "%s: Pushing FW onto adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302662 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2663 ioc->cached_fw, CAN_SLEEP)) < 0) {
2664 printk(MYIOC_s_WARN_FMT
2665 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002666 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 }
2668 }
2669
Kashyap, Desai71278192009-05-29 16:53:14 +05302670 /*
2671 * Put the controller into ready state (if its not already)
2672 */
2673 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {
2674 if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
2675 CAN_SLEEP)) {
2676 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)
2677 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit "
2678 "reset failed to put ioc in ready state!\n",
2679 ioc->name, __func__);
2680 } else
2681 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset "
2682 "failed!\n", ioc->name, __func__);
2683 }
2684
2685
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 /* Disable adapter interrupts! */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302687 synchronize_irq(ioc->pcidev->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2689 ioc->active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302690
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 /* Clear any lingering interrupt */
2692 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302693 CHIPREG_READ32(&ioc->chip->IntStatus);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694
2695 if (ioc->alloc != NULL) {
2696 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002697 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2698 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 pci_free_consistent(ioc->pcidev, sz,
2700 ioc->alloc, ioc->alloc_dma);
2701 ioc->reply_frames = NULL;
2702 ioc->req_frames = NULL;
2703 ioc->alloc = NULL;
2704 ioc->alloc_total -= sz;
2705 }
2706
2707 if (ioc->sense_buf_pool != NULL) {
2708 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2709 pci_free_consistent(ioc->pcidev, sz,
2710 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2711 ioc->sense_buf_pool = NULL;
2712 ioc->alloc_total -= sz;
2713 }
2714
2715 if (ioc->events != NULL){
2716 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2717 kfree(ioc->events);
2718 ioc->events = NULL;
2719 ioc->alloc_total -= sz;
2720 }
2721
Prakash, Sathya984621b2008-01-11 14:42:17 +05302722 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002724 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002725 mpt_inactive_raid_list_free(ioc);
2726 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002727 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002728 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002729 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730
2731 if (ioc->spi_data.pIocPg4 != NULL) {
2732 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302733 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 ioc->spi_data.pIocPg4,
2735 ioc->spi_data.IocPg4_dma);
2736 ioc->spi_data.pIocPg4 = NULL;
2737 ioc->alloc_total -= sz;
2738 }
2739
2740 if (ioc->ReqToChain != NULL) {
2741 kfree(ioc->ReqToChain);
2742 kfree(ioc->RequestNB);
2743 ioc->ReqToChain = NULL;
2744 }
2745
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002746 kfree(ioc->ChainToChain);
2747 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002748
2749 if (ioc->HostPageBuffer != NULL) {
2750 if((ret = mpt_host_page_access_control(ioc,
2751 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002752 printk(MYIOC_s_ERR_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302753 ": %s: host page buffers free failed (%d)!\n",
2754 ioc->name, __func__, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002755 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302756 dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2757 "HostPageBuffer free @ %p, sz=%d bytes\n",
2758 ioc->name, ioc->HostPageBuffer,
2759 ioc->HostPageBuffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002760 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002761 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002762 ioc->HostPageBuffer = NULL;
2763 ioc->HostPageBuffer_sz = 0;
2764 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2765 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766
Kashyap, Desai2f187862009-05-29 16:52:37 +05302767 pci_set_drvdata(ioc->pcidev, NULL);
2768}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002770/**
2771 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 * @ioc: Pointer to MPT adapter structure
2773 *
2774 * This routine unregisters h/w resources and frees all alloc'd memory
2775 * associated with a MPT adapter structure.
2776 */
2777static void
2778mpt_adapter_dispose(MPT_ADAPTER *ioc)
2779{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002780 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002782 if (ioc == NULL)
2783 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002785 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002787 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002789 if (ioc->pci_irq != -1) {
2790 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302791 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002792 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002793 ioc->pci_irq = -1;
2794 }
2795
2796 if (ioc->memmap != NULL) {
2797 iounmap(ioc->memmap);
2798 ioc->memmap = NULL;
2799 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302801 pci_disable_device(ioc->pcidev);
2802 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2803
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002805 if (ioc->mtrr_reg > 0) {
2806 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002807 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002808 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809#endif
2810
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002811 /* Zap the adapter lookup ptr! */
2812 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002814 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002815 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2816 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002817
2818 if (ioc->alt_ioc)
2819 ioc->alt_ioc->alt_ioc = NULL;
2820
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002821 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822}
2823
2824/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002825/**
2826 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827 * @ioc: Pointer to MPT adapter structure
2828 */
2829static void
2830MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2831{
2832 int i = 0;
2833
2834 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302835 if (ioc->prod_name)
2836 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 printk("Capabilities={");
2838
2839 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2840 printk("Initiator");
2841 i++;
2842 }
2843
2844 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2845 printk("%sTarget", i ? "," : "");
2846 i++;
2847 }
2848
2849 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2850 printk("%sLAN", i ? "," : "");
2851 i++;
2852 }
2853
2854#if 0
2855 /*
2856 * This would probably evoke more questions than it's worth
2857 */
2858 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2859 printk("%sLogBusAddr", i ? "," : "");
2860 i++;
2861 }
2862#endif
2863
2864 printk("}\n");
2865}
2866
2867/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002868/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2870 * @ioc: Pointer to MPT_ADAPTER structure
2871 * @force: Force hard KickStart of IOC
2872 * @sleepFlag: Specifies whether the process can sleep
2873 *
2874 * Returns:
2875 * 1 - DIAG reset and READY
2876 * 0 - READY initially OR soft reset and READY
2877 * -1 - Any failure on KickStart
2878 * -2 - Msg Unit Reset Failed
2879 * -3 - IO Unit Reset Failed
2880 * -4 - IOC owned by a PEER
2881 */
2882static int
2883MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2884{
2885 u32 ioc_state;
2886 int statefault = 0;
2887 int cntdn;
2888 int hard_reset_done = 0;
2889 int r;
2890 int ii;
2891 int whoinit;
2892
2893 /* Get current [raw] IOC state */
2894 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002895 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896
2897 /*
2898 * Check to see if IOC got left/stuck in doorbell handshake
2899 * grip of death. If so, hard reset the IOC.
2900 */
2901 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2902 statefault = 1;
2903 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2904 ioc->name);
2905 }
2906
2907 /* Is it already READY? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302908 if (!statefault &&
2909 ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) {
2910 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2911 "IOC is in READY state\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 return 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302913 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914
2915 /*
2916 * Check to see if IOC is in FAULT state.
2917 */
2918 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2919 statefault = 2;
2920 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002921 ioc->name);
2922 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2923 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 }
2925
2926 /*
2927 * Hmmm... Did it get left operational?
2928 */
2929 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302930 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 ioc->name));
2932
2933 /* Check WhoInit.
2934 * If PCI Peer, exit.
2935 * Else, if no fault conditions are present, issue a MessageUnitReset
2936 * Else, fall through to KickStart case
2937 */
2938 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002939 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2940 "whoinit 0x%x statefault %d force %d\n",
2941 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 if (whoinit == MPI_WHOINIT_PCI_PEER)
2943 return -4;
2944 else {
2945 if ((statefault == 0 ) && (force == 0)) {
2946 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2947 return 0;
2948 }
2949 statefault = 3;
2950 }
2951 }
2952
2953 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2954 if (hard_reset_done < 0)
2955 return -1;
2956
2957 /*
2958 * Loop here waiting for IOC to come READY.
2959 */
2960 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002961 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962
2963 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2964 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2965 /*
2966 * BIOS or previous driver load left IOC in OP state.
2967 * Reset messaging FIFOs.
2968 */
2969 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2970 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2971 return -2;
2972 }
2973 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2974 /*
2975 * Something is wrong. Try to get IOC back
2976 * to a known state.
2977 */
2978 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2979 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2980 return -3;
2981 }
2982 }
2983
2984 ii++; cntdn--;
2985 if (!cntdn) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302986 printk(MYIOC_s_ERR_FMT
2987 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
2988 ioc->name, ioc_state, (int)((ii+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 return -ETIME;
2990 }
2991
2992 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002993 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 } else {
2995 mdelay (1); /* 1 msec delay */
2996 }
2997
2998 }
2999
3000 if (statefault < 3) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303001 printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name,
3002 statefault == 1 ? "stuck handshake" : "IOC FAULT");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 }
3004
3005 return hard_reset_done;
3006}
3007
3008/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003009/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 * mpt_GetIocState - Get the current state of a MPT adapter.
3011 * @ioc: Pointer to MPT_ADAPTER structure
3012 * @cooked: Request raw or cooked IOC state
3013 *
3014 * Returns all IOC Doorbell register bits if cooked==0, else just the
3015 * Doorbell bits in MPI_IOC_STATE_MASK.
3016 */
3017u32
3018mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
3019{
3020 u32 s, sc;
3021
3022 /* Get! */
3023 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 sc = s & MPI_IOC_STATE_MASK;
3025
3026 /* Save! */
3027 ioc->last_state = sc;
3028
3029 return cooked ? sc : s;
3030}
3031
3032/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003033/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 * GetIocFacts - Send IOCFacts request to MPT adapter.
3035 * @ioc: Pointer to MPT_ADAPTER structure
3036 * @sleepFlag: Specifies whether the process can sleep
3037 * @reason: If recovery, only update facts.
3038 *
3039 * Returns 0 for success, non-zero for failure.
3040 */
3041static int
3042GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
3043{
3044 IOCFacts_t get_facts;
3045 IOCFactsReply_t *facts;
3046 int r;
3047 int req_sz;
3048 int reply_sz;
3049 int sz;
3050 u32 status, vv;
3051 u8 shiftFactor=1;
3052
3053 /* IOC *must* NOT be in RESET state! */
3054 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303055 printk(KERN_ERR MYNAM
3056 ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
3057 ioc->name, ioc->last_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 return -44;
3059 }
3060
3061 facts = &ioc->facts;
3062
3063 /* Destination (reply area)... */
3064 reply_sz = sizeof(*facts);
3065 memset(facts, 0, reply_sz);
3066
3067 /* Request area (get_facts on the stack right now!) */
3068 req_sz = sizeof(get_facts);
3069 memset(&get_facts, 0, req_sz);
3070
3071 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
3072 /* Assert: All other get_facts fields are zero! */
3073
Prakash, Sathya436ace72007-07-24 15:42:08 +05303074 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003075 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 ioc->name, req_sz, reply_sz));
3077
3078 /* No non-zero fields in the get_facts request are greater than
3079 * 1 byte in size, so we can just fire it off as is.
3080 */
3081 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3082 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3083 if (r != 0)
3084 return r;
3085
3086 /*
3087 * Now byte swap (GRRR) the necessary fields before any further
3088 * inspection of reply contents.
3089 *
3090 * But need to do some sanity checks on MsgLength (byte) field
3091 * to make sure we don't zero IOC's req_sz!
3092 */
3093 /* Did we get a valid reply? */
3094 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3095 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3096 /*
3097 * If not been here, done that, save off first WhoInit value
3098 */
3099 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3100 ioc->FirstWhoInit = facts->WhoInit;
3101 }
3102
3103 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3104 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3105 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3106 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3107 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003108 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 /* CHECKME! IOCStatus, IOCLogInfo */
3110
3111 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3112 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3113
3114 /*
3115 * FC f/w version changed between 1.1 and 1.2
3116 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3117 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3118 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303119 if (facts->MsgVersion < MPI_VERSION_01_02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 /*
3121 * Handle old FC f/w style, convert to new...
3122 */
3123 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3124 facts->FWVersion.Word =
3125 ((oldv<<12) & 0xFF000000) |
3126 ((oldv<<8) & 0x000FFF00);
3127 } else
3128 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3129
3130 facts->ProductID = le16_to_cpu(facts->ProductID);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303131
Eric Mooreb506ade2007-01-29 09:45:37 -07003132 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3133 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3134 ioc->ir_firmware = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303135
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 facts->CurrentHostMfaHighAddr =
3137 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3138 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3139 facts->CurrentSenseBufferHighAddr =
3140 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3141 facts->CurReplyFrameSize =
3142 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003143 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144
3145 /*
3146 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3147 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3148 * to 14 in MPI-1.01.0x.
3149 */
3150 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
Kashyap, Desai2f187862009-05-29 16:52:37 +05303151 facts->MsgVersion > MPI_VERSION_01_00) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3153 }
3154
3155 sz = facts->FWImageSize;
3156 if ( sz & 0x01 )
3157 sz += 1;
3158 if ( sz & 0x02 )
3159 sz += 2;
3160 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003161
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162 if (!facts->RequestFrameSize) {
3163 /* Something is wrong! */
3164 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3165 ioc->name);
3166 return -55;
3167 }
3168
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003169 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 vv = ((63 / (sz * 4)) + 1) & 0x03;
3171 ioc->NB_for_64_byte_frame = vv;
3172 while ( sz )
3173 {
3174 shiftFactor++;
3175 sz = sz >> 1;
3176 }
3177 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303178 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003179 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3180 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003181
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3183 /*
3184 * Set values for this IOC's request & reply frame sizes,
3185 * and request & reply queue depths...
3186 */
3187 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3188 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3189 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3190 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3191
Prakash, Sathya436ace72007-07-24 15:42:08 +05303192 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303194 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 ioc->name, ioc->req_sz, ioc->req_depth));
3196
3197 /* Get port facts! */
3198 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3199 return r;
3200 }
3201 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003202 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3204 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3205 RequestFrameSize)/sizeof(u32)));
3206 return -66;
3207 }
3208
3209 return 0;
3210}
3211
3212/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003213/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 * GetPortFacts - Send PortFacts request to MPT adapter.
3215 * @ioc: Pointer to MPT_ADAPTER structure
3216 * @portnum: Port number
3217 * @sleepFlag: Specifies whether the process can sleep
3218 *
3219 * Returns 0 for success, non-zero for failure.
3220 */
3221static int
3222GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3223{
3224 PortFacts_t get_pfacts;
3225 PortFactsReply_t *pfacts;
3226 int ii;
3227 int req_sz;
3228 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003229 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230
3231 /* IOC *must* NOT be in RESET state! */
3232 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003233 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3234 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 return -4;
3236 }
3237
3238 pfacts = &ioc->pfacts[portnum];
3239
3240 /* Destination (reply area)... */
3241 reply_sz = sizeof(*pfacts);
3242 memset(pfacts, 0, reply_sz);
3243
3244 /* Request area (get_pfacts on the stack right now!) */
3245 req_sz = sizeof(get_pfacts);
3246 memset(&get_pfacts, 0, req_sz);
3247
3248 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3249 get_pfacts.PortNumber = portnum;
3250 /* Assert: All other get_pfacts fields are zero! */
3251
Prakash, Sathya436ace72007-07-24 15:42:08 +05303252 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 ioc->name, portnum));
3254
3255 /* No non-zero fields in the get_pfacts request are greater than
3256 * 1 byte in size, so we can just fire it off as is.
3257 */
3258 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3259 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3260 if (ii != 0)
3261 return ii;
3262
3263 /* Did we get a valid reply? */
3264
3265 /* Now byte swap the necessary fields in the response. */
3266 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3267 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3268 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3269 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3270 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3271 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3272 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3273 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3274 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3275
Eric Moore793955f2007-01-29 09:42:20 -07003276 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3277 pfacts->MaxDevices;
3278 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3279 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3280
3281 /*
3282 * Place all the devices on channels
3283 *
3284 * (for debuging)
3285 */
3286 if (mpt_channel_mapping) {
3287 ioc->devices_per_bus = 1;
3288 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3289 }
3290
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291 return 0;
3292}
3293
3294/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003295/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 * SendIocInit - Send IOCInit request to MPT adapter.
3297 * @ioc: Pointer to MPT_ADAPTER structure
3298 * @sleepFlag: Specifies whether the process can sleep
3299 *
3300 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3301 *
3302 * Returns 0 for success, non-zero for failure.
3303 */
3304static int
3305SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3306{
3307 IOCInit_t ioc_init;
3308 MPIDefaultReply_t init_reply;
3309 u32 state;
3310 int r;
3311 int count;
3312 int cntdn;
3313
3314 memset(&ioc_init, 0, sizeof(ioc_init));
3315 memset(&init_reply, 0, sizeof(init_reply));
3316
3317 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3318 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3319
3320 /* If we are in a recovery mode and we uploaded the FW image,
3321 * then this pointer is not NULL. Skip the upload a second time.
3322 * Set this flag if cached_fw set for either IOC.
3323 */
3324 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3325 ioc->upload_fw = 1;
3326 else
3327 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303328 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3330
Eric Moore793955f2007-01-29 09:42:20 -07003331 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3332 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303333
Prakash, Sathya436ace72007-07-24 15:42:08 +05303334 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003335 ioc->name, ioc->facts.MsgVersion));
3336 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3337 // set MsgVersion and HeaderVersion host driver was built with
3338 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3339 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003341 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3342 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3343 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3344 return -99;
3345 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3347
Kashyap, Desai2f187862009-05-29 16:52:37 +05303348 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 /* Save the upper 32-bits of the request
3350 * (reply) and sense buffers.
3351 */
3352 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3353 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3354 } else {
3355 /* Force 32-bit addressing */
3356 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3357 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3358 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003359
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3361 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003362 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3363 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364
Prakash, Sathya436ace72007-07-24 15:42:08 +05303365 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 ioc->name, &ioc_init));
3367
3368 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3369 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003370 if (r != 0) {
3371 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003373 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374
3375 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003376 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377 */
3378
Prakash, Sathya436ace72007-07-24 15:42:08 +05303379 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003381
3382 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3383 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386
3387 /* YIKES! SUPER IMPORTANT!!!
3388 * Poll IocState until _OPERATIONAL while IOC is doing
3389 * LoopInit and TargetDiscovery!
3390 */
3391 count = 0;
3392 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3393 state = mpt_GetIocState(ioc, 1);
3394 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3395 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003396 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 } else {
3398 mdelay(1);
3399 }
3400
3401 if (!cntdn) {
3402 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3403 ioc->name, (int)((count+5)/HZ));
3404 return -9;
3405 }
3406
3407 state = mpt_GetIocState(ioc, 1);
3408 count++;
3409 }
Eric Moore29dd3602007-09-14 18:46:51 -06003410 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 ioc->name, count));
3412
Eric Mooreba856d32006-07-11 17:34:01 -06003413 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 return r;
3415}
3416
3417/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003418/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 * SendPortEnable - Send PortEnable request to MPT adapter port.
3420 * @ioc: Pointer to MPT_ADAPTER structure
3421 * @portnum: Port number to enable
3422 * @sleepFlag: Specifies whether the process can sleep
3423 *
3424 * Send PortEnable to bring IOC to OPERATIONAL state.
3425 *
3426 * Returns 0 for success, non-zero for failure.
3427 */
3428static int
3429SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3430{
3431 PortEnable_t port_enable;
3432 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003433 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 int req_sz;
3435 int reply_sz;
3436
3437 /* Destination... */
3438 reply_sz = sizeof(MPIDefaultReply_t);
3439 memset(&reply_buf, 0, reply_sz);
3440
3441 req_sz = sizeof(PortEnable_t);
3442 memset(&port_enable, 0, req_sz);
3443
3444 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3445 port_enable.PortNumber = portnum;
3446/* port_enable.ChainOffset = 0; */
3447/* port_enable.MsgFlags = 0; */
3448/* port_enable.MsgContext = 0; */
3449
Prakash, Sathya436ace72007-07-24 15:42:08 +05303450 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 ioc->name, portnum, &port_enable));
3452
3453 /* RAID FW may take a long time to enable
3454 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003455 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003456 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3457 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3458 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003459 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003460 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3461 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3462 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003464 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465}
3466
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003467/**
3468 * mpt_alloc_fw_memory - allocate firmware memory
3469 * @ioc: Pointer to MPT_ADAPTER structure
3470 * @size: total FW bytes
3471 *
3472 * If memory has already been allocated, the same (cached) value
3473 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303474 *
3475 * Return 0 if successfull, or non-zero for failure
3476 **/
3477int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3479{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303480 int rc;
3481
3482 if (ioc->cached_fw) {
3483 rc = 0; /* use already allocated memory */
3484 goto out;
3485 }
3486 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3488 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303489 rc = 0;
3490 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303492 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3493 if (!ioc->cached_fw) {
3494 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3495 ioc->name);
3496 rc = -1;
3497 } else {
3498 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3499 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3500 ioc->alloc_total += size;
3501 rc = 0;
3502 }
3503 out:
3504 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303506
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003507/**
3508 * mpt_free_fw_memory - free firmware memory
3509 * @ioc: Pointer to MPT_ADAPTER structure
3510 *
3511 * If alt_img is NULL, delete from ioc structure.
3512 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303513 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514void
3515mpt_free_fw_memory(MPT_ADAPTER *ioc)
3516{
3517 int sz;
3518
Prakash, Sathya984621b2008-01-11 14:42:17 +05303519 if (!ioc->cached_fw)
3520 return;
3521
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303523 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3524 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003525 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303526 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528}
3529
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003531/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3533 * @ioc: Pointer to MPT_ADAPTER structure
3534 * @sleepFlag: Specifies whether the process can sleep
3535 *
3536 * Returns 0 for success, >0 for handshake failure
3537 * <0 for fw upload failure.
3538 *
3539 * Remark: If bound IOC and a successful FWUpload was performed
3540 * on the bound IOC, the second image is discarded
3541 * and memory is free'd. Both channels must upload to prevent
3542 * IOC from running in degraded mode.
3543 */
3544static int
3545mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3546{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 u8 reply[sizeof(FWUploadReply_t)];
3548 FWUpload_t *prequest;
3549 FWUploadReply_t *preply;
3550 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551 u32 flagsLength;
3552 int ii, sz, reply_sz;
3553 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303554 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555 /* If the image size is 0, we are done.
3556 */
3557 if ((sz = ioc->facts.FWImageSize) == 0)
3558 return 0;
3559
Prakash, Sathya984621b2008-01-11 14:42:17 +05303560 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3561 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562
Eric Moore29dd3602007-09-14 18:46:51 -06003563 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3564 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003565
Eric Moorebc6e0892007-09-29 10:16:28 -06003566 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3567 kzalloc(ioc->req_sz, GFP_KERNEL);
3568 if (!prequest) {
3569 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3570 "while allocating memory \n", ioc->name));
3571 mpt_free_fw_memory(ioc);
3572 return -ENOMEM;
3573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574
Eric Moorebc6e0892007-09-29 10:16:28 -06003575 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576
3577 reply_sz = sizeof(reply);
3578 memset(preply, 0, reply_sz);
3579
3580 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3581 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3582
3583 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3584 ptcsge->DetailsLength = 12;
3585 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3586 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003587 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303590 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3591 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3592 ioc->SGE_size;
3593 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3594 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3595 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003596 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303598 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3599 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600
Kashyap, Desai2f187862009-05-29 16:52:37 +05303601 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
3602 "rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603
3604 cmdStatus = -EFAULT;
3605 if (ii == 0) {
3606 /* Handshake transfer was complete and successful.
3607 * Check the Reply Frame.
3608 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303609 int status;
3610 status = le16_to_cpu(preply->IOCStatus) &
3611 MPI_IOCSTATUS_MASK;
3612 if (status == MPI_IOCSTATUS_SUCCESS &&
3613 ioc->facts.FWImageSize ==
3614 le32_to_cpu(preply->ActualImageSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 cmdStatus = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303617 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 ioc->name, cmdStatus));
3619
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003620
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 if (cmdStatus) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303622 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
3623 "freeing image \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 mpt_free_fw_memory(ioc);
3625 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003626 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627
3628 return cmdStatus;
3629}
3630
3631/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003632/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 * mpt_downloadboot - DownloadBoot code
3634 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003635 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 * @sleepFlag: Specifies whether the process can sleep
3637 *
3638 * FwDownloadBoot requires Programmed IO access.
3639 *
3640 * Returns 0 for success
3641 * -1 FW Image size is 0
3642 * -2 No valid cached_fw Pointer
3643 * <0 for fw upload failure.
3644 */
3645static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003646mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 MpiExtImageHeader_t *pExtImage;
3649 u32 fwSize;
3650 u32 diag0val;
3651 int count;
3652 u32 *ptrFw;
3653 u32 diagRwData;
3654 u32 nextImage;
3655 u32 load_addr;
3656 u32 ioc_state=0;
3657
Prakash, Sathya436ace72007-07-24 15:42:08 +05303658 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003659 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003660
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3662 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3663 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3664 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3665 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3666 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3667
3668 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3669
3670 /* wait 1 msec */
3671 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003672 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 } else {
3674 mdelay (1);
3675 }
3676
3677 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3678 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3679
3680 for (count = 0; count < 30; count ++) {
3681 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3682 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303683 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 ioc->name, count));
3685 break;
3686 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003687 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003689 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003691 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 }
3693 }
3694
3695 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303696 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003697 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 ioc->name, diag0val));
3699 return -3;
3700 }
3701
3702 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3703 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3704 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3705 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3706 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3707 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3708
3709 /* Set the DiagRwEn and Disable ARM bits */
3710 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3711
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 fwSize = (pFwHeader->ImageSize + 3)/4;
3713 ptrFw = (u32 *) pFwHeader;
3714
3715 /* Write the LoadStartAddress to the DiagRw Address Register
3716 * using Programmed IO
3717 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003718 if (ioc->errata_flag_1064)
3719 pci_enable_io_access(ioc->pcidev);
3720
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303722 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723 ioc->name, pFwHeader->LoadStartAddress));
3724
Prakash, Sathya436ace72007-07-24 15:42:08 +05303725 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726 ioc->name, fwSize*4, ptrFw));
3727 while (fwSize--) {
3728 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3729 }
3730
3731 nextImage = pFwHeader->NextImageHeaderOffset;
3732 while (nextImage) {
3733 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3734
3735 load_addr = pExtImage->LoadStartAddress;
3736
3737 fwSize = (pExtImage->ImageSize + 3) >> 2;
3738 ptrFw = (u32 *)pExtImage;
3739
Prakash, Sathya436ace72007-07-24 15:42:08 +05303740 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003741 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3743
3744 while (fwSize--) {
3745 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3746 }
3747 nextImage = pExtImage->NextImageHeaderOffset;
3748 }
3749
3750 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303751 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3753
3754 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303755 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3757
3758 /* Clear the internal flash bad bit - autoincrementing register,
3759 * so must do two writes.
3760 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003761 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003762 /*
3763 * 1030 and 1035 H/W errata, workaround to access
3764 * the ClearFlashBadSignatureBit
3765 */
3766 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3767 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3768 diagRwData |= 0x40000000;
3769 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3770 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3771
3772 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3773 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3774 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3775 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3776
3777 /* wait 1 msec */
3778 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003779 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003780 } else {
3781 mdelay (1);
3782 }
3783 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003785 if (ioc->errata_flag_1064)
3786 pci_disable_io_access(ioc->pcidev);
3787
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303789 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003790 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003792 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303793 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 ioc->name, diag0val));
3795 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3796
3797 /* Write 0xFF to reset the sequencer */
3798 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3799
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003800 if (ioc->bus_type == SAS) {
3801 ioc_state = mpt_GetIocState(ioc, 0);
3802 if ( (GetIocFacts(ioc, sleepFlag,
3803 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303804 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003805 ioc->name, ioc_state));
3806 return -EFAULT;
3807 }
3808 }
3809
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810 for (count=0; count<HZ*20; count++) {
3811 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303812 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3813 "downloadboot successful! (count=%d) IocState=%x\n",
3814 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003815 if (ioc->bus_type == SAS) {
3816 return 0;
3817 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303819 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3820 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 ioc->name));
3822 return -EFAULT;
3823 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303824 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3825 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826 ioc->name));
3827 return 0;
3828 }
3829 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003830 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 } else {
3832 mdelay (10);
3833 }
3834 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303835 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3836 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837 return -EFAULT;
3838}
3839
3840/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003841/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842 * KickStart - Perform hard reset of MPT adapter.
3843 * @ioc: Pointer to MPT_ADAPTER structure
3844 * @force: Force hard reset
3845 * @sleepFlag: Specifies whether the process can sleep
3846 *
3847 * This routine places MPT adapter in diagnostic mode via the
3848 * WriteSequence register, and then performs a hard reset of adapter
3849 * via the Diagnostic register.
3850 *
3851 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3852 * or NO_SLEEP (interrupt thread, use mdelay)
3853 * force - 1 if doorbell active, board fault state
3854 * board operational, IOC_RECOVERY or
3855 * IOC_BRINGUP and there is an alt_ioc.
3856 * 0 else
3857 *
3858 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003859 * 1 - hard reset, READY
3860 * 0 - no reset due to History bit, READY
3861 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862 * OR reset but failed to come READY
3863 * -2 - no reset, could not enter DIAG mode
3864 * -3 - reset but bad FW bit
3865 */
3866static int
3867KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3868{
3869 int hard_reset_done = 0;
3870 u32 ioc_state=0;
3871 int cnt,cntdn;
3872
Eric Moore29dd3602007-09-14 18:46:51 -06003873 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003874 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875 /* Always issue a Msg Unit Reset first. This will clear some
3876 * SCSI bus hang conditions.
3877 */
3878 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3879
3880 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003881 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882 } else {
3883 mdelay (1000);
3884 }
3885 }
3886
3887 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3888 if (hard_reset_done < 0)
3889 return hard_reset_done;
3890
Prakash, Sathya436ace72007-07-24 15:42:08 +05303891 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003892 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893
3894 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3895 for (cnt=0; cnt<cntdn; cnt++) {
3896 ioc_state = mpt_GetIocState(ioc, 1);
3897 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303898 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 ioc->name, cnt));
3900 return hard_reset_done;
3901 }
3902 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003903 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 } else {
3905 mdelay (10);
3906 }
3907 }
3908
Eric Moore29dd3602007-09-14 18:46:51 -06003909 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3910 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 return -1;
3912}
3913
3914/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003915/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916 * mpt_diag_reset - Perform hard reset of the adapter.
3917 * @ioc: Pointer to MPT_ADAPTER structure
3918 * @ignore: Set if to honor and clear to ignore
3919 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003920 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921 * else set to NO_SLEEP (use mdelay instead)
3922 *
3923 * This routine places the adapter in diagnostic mode via the
3924 * WriteSequence register and then performs a hard reset of adapter
3925 * via the Diagnostic register. Adapter should be in ready state
3926 * upon successful completion.
3927 *
3928 * Returns: 1 hard reset successful
3929 * 0 no reset performed because reset history bit set
3930 * -2 enabling diagnostic mode failed
3931 * -3 diagnostic reset failed
3932 */
3933static int
3934mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3935{
3936 u32 diag0val;
3937 u32 doorbell;
3938 int hard_reset_done = 0;
3939 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303941 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942
Eric Moorecd2c6192007-01-29 09:47:47 -07003943 /* Clear any existing interrupts */
3944 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3945
Eric Moore87cf8982006-06-27 16:09:26 -06003946 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303947
3948 if (!ignore)
3949 return 0;
3950
Prakash, Sathya436ace72007-07-24 15:42:08 +05303951 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003952 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003953 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3954 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3955 if (sleepFlag == CAN_SLEEP)
3956 msleep(1);
3957 else
3958 mdelay(1);
3959
3960 for (count = 0; count < 60; count ++) {
3961 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3962 doorbell &= MPI_IOC_STATE_MASK;
3963
Prakash, Sathya436ace72007-07-24 15:42:08 +05303964 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003965 "looking for READY STATE: doorbell=%x"
3966 " count=%d\n",
3967 ioc->name, doorbell, count));
Kashyap, Desai2f187862009-05-29 16:52:37 +05303968
Eric Moore87cf8982006-06-27 16:09:26 -06003969 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003970 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003971 }
3972
3973 /* wait 1 sec */
3974 if (sleepFlag == CAN_SLEEP)
3975 msleep(1000);
3976 else
3977 mdelay(1000);
3978 }
3979 return -1;
3980 }
3981
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982 /* Use "Diagnostic reset" method! (only thing available!) */
3983 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3984
Prakash, Sathya436ace72007-07-24 15:42:08 +05303985 if (ioc->debug_level & MPT_DEBUG) {
3986 if (ioc->alt_ioc)
3987 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3988 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303990 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991
3992 /* Do the reset if we are told to ignore the reset history
3993 * or if the reset history is 0
3994 */
3995 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3996 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3997 /* Write magic sequence to WriteSequence register
3998 * Loop until in diagnostic mode
3999 */
4000 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4001 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4002 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4003 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4004 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4005 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4006
4007 /* wait 100 msec */
4008 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004009 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 } else {
4011 mdelay (100);
4012 }
4013
4014 count++;
4015 if (count > 20) {
4016 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4017 ioc->name, diag0val);
4018 return -2;
4019
4020 }
4021
4022 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4023
Prakash, Sathya436ace72007-07-24 15:42:08 +05304024 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 ioc->name, diag0val));
4026 }
4027
Prakash, Sathya436ace72007-07-24 15:42:08 +05304028 if (ioc->debug_level & MPT_DEBUG) {
4029 if (ioc->alt_ioc)
4030 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4031 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304033 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 /*
4035 * Disable the ARM (Bug fix)
4036 *
4037 */
4038 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004039 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040
4041 /*
4042 * Now hit the reset bit in the Diagnostic register
4043 * (THE BIG HAMMER!) (Clears DRWE bit).
4044 */
4045 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
4046 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304047 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 ioc->name));
4049
4050 /*
4051 * Call each currently registered protocol IOC reset handler
4052 * with pre-reset indication.
4053 * NOTE: If we're doing _IOC_BRINGUP, there can be no
4054 * MptResetHandlers[] registered yet.
4055 */
4056 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304057 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 int r = 0;
4059
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304060 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
4061 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304062 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4063 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304064 ioc->name, cb_idx));
4065 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304067 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4068 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304069 ioc->name, ioc->alt_ioc->name, cb_idx));
4070 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071 }
4072 }
4073 }
4074 /* FIXME? Examine results here? */
4075 }
4076
Eric Moore0ccdb002006-07-11 17:33:13 -06004077 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304078 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06004079 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304080 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4081 else
4082 cached_fw = NULL;
4083 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084 /* If the DownloadBoot operation fails, the
4085 * IOC will be left unusable. This is a fatal error
4086 * case. _diag_reset will return < 0
4087 */
4088 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304089 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4091 break;
4092 }
4093
Prakash, Sathya436ace72007-07-24 15:42:08 +05304094 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304095 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096 /* wait 1 sec */
4097 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004098 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099 } else {
4100 mdelay (1000);
4101 }
4102 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304103 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004104 printk(MYIOC_s_WARN_FMT
4105 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106 }
4107
4108 } else {
4109 /* Wait for FW to reload and for board
4110 * to go to the READY state.
4111 * Maximum wait is 60 seconds.
4112 * If fail, no error will check again
4113 * with calling program.
4114 */
4115 for (count = 0; count < 60; count ++) {
4116 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4117 doorbell &= MPI_IOC_STATE_MASK;
4118
Kashyap, Desai2f187862009-05-29 16:52:37 +05304119 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4120 "looking for READY STATE: doorbell=%x"
4121 " count=%d\n", ioc->name, doorbell, count));
4122
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123 if (doorbell == MPI_IOC_STATE_READY) {
4124 break;
4125 }
4126
4127 /* wait 1 sec */
4128 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004129 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130 } else {
4131 mdelay (1000);
4132 }
4133 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05304134
4135 if (doorbell != MPI_IOC_STATE_READY)
4136 printk(MYIOC_s_ERR_FMT "Failed to come READY "
4137 "after reset! IocState=%x", ioc->name,
4138 doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139 }
4140 }
4141
4142 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304143 if (ioc->debug_level & MPT_DEBUG) {
4144 if (ioc->alt_ioc)
4145 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4146 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4147 ioc->name, diag0val, diag1val));
4148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149
4150 /* Clear RESET_HISTORY bit! Place board in the
4151 * diagnostic mode to update the diag register.
4152 */
4153 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4154 count = 0;
4155 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4156 /* Write magic sequence to WriteSequence register
4157 * Loop until in diagnostic mode
4158 */
4159 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4160 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4161 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4162 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4163 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4164 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4165
4166 /* wait 100 msec */
4167 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004168 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169 } else {
4170 mdelay (100);
4171 }
4172
4173 count++;
4174 if (count > 20) {
4175 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4176 ioc->name, diag0val);
4177 break;
4178 }
4179 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4180 }
4181 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4182 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4183 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4184 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4185 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4186 ioc->name);
4187 }
4188
4189 /* Disable Diagnostic Mode
4190 */
4191 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4192
4193 /* Check FW reload status flags.
4194 */
4195 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4196 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4197 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4198 ioc->name, diag0val);
4199 return -3;
4200 }
4201
Prakash, Sathya436ace72007-07-24 15:42:08 +05304202 if (ioc->debug_level & MPT_DEBUG) {
4203 if (ioc->alt_ioc)
4204 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4205 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304207 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208
4209 /*
4210 * Reset flag that says we've enabled event notification
4211 */
4212 ioc->facts.EventState = 0;
4213
4214 if (ioc->alt_ioc)
4215 ioc->alt_ioc->facts.EventState = 0;
4216
4217 return hard_reset_done;
4218}
4219
4220/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004221/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222 * SendIocReset - Send IOCReset request to MPT adapter.
4223 * @ioc: Pointer to MPT_ADAPTER structure
4224 * @reset_type: reset type, expected values are
4225 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004226 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 *
4228 * Send IOCReset request to the MPT adapter.
4229 *
4230 * Returns 0 for success, non-zero for failure.
4231 */
4232static int
4233SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4234{
4235 int r;
4236 u32 state;
4237 int cntdn, count;
4238
Prakash, Sathya436ace72007-07-24 15:42:08 +05304239 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 ioc->name, reset_type));
4241 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4242 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4243 return r;
4244
4245 /* FW ACK'd request, wait for READY state
4246 */
4247 count = 0;
4248 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4249
4250 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4251 cntdn--;
4252 count++;
4253 if (!cntdn) {
4254 if (sleepFlag != CAN_SLEEP)
4255 count *= 10;
4256
Kashyap, Desai2f187862009-05-29 16:52:37 +05304257 printk(MYIOC_s_ERR_FMT
4258 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
4259 ioc->name, state, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 return -ETIME;
4261 }
4262
4263 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004264 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265 } else {
4266 mdelay (1); /* 1 msec delay */
4267 }
4268 }
4269
4270 /* TODO!
4271 * Cleanup all event stuff for this IOC; re-issue EventNotification
4272 * request if needed.
4273 */
4274 if (ioc->facts.Function)
4275 ioc->facts.EventState = 0;
4276
4277 return 0;
4278}
4279
4280/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004281/**
4282 * initChainBuffers - Allocate memory for and initialize chain buffers
4283 * @ioc: Pointer to MPT_ADAPTER structure
4284 *
4285 * Allocates memory for and initializes chain buffers,
4286 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 */
4288static int
4289initChainBuffers(MPT_ADAPTER *ioc)
4290{
4291 u8 *mem;
4292 int sz, ii, num_chain;
4293 int scale, num_sge, numSGE;
4294
4295 /* ReqToChain size must equal the req_depth
4296 * index = req_idx
4297 */
4298 if (ioc->ReqToChain == NULL) {
4299 sz = ioc->req_depth * sizeof(int);
4300 mem = kmalloc(sz, GFP_ATOMIC);
4301 if (mem == NULL)
4302 return -1;
4303
4304 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304305 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 ioc->name, mem, sz));
4307 mem = kmalloc(sz, GFP_ATOMIC);
4308 if (mem == NULL)
4309 return -1;
4310
4311 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304312 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 ioc->name, mem, sz));
4314 }
4315 for (ii = 0; ii < ioc->req_depth; ii++) {
4316 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4317 }
4318
4319 /* ChainToChain size must equal the total number
4320 * of chain buffers to be allocated.
4321 * index = chain_idx
4322 *
4323 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004324 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325 *
4326 * num_sge = num sge in request frame + last chain buffer
4327 * scale = num sge per chain buffer if no chain element
4328 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304329 scale = ioc->req_sz / ioc->SGE_size;
4330 if (ioc->sg_addr_size == sizeof(u64))
4331 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304333 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304335 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304337 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304339 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4340 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004341 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304342 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 ioc->name, num_sge, numSGE));
4344
Kashyap, Desai2f187862009-05-29 16:52:37 +05304345 if (ioc->bus_type == FC) {
4346 if (numSGE > MPT_SCSI_FC_SG_DEPTH)
4347 numSGE = MPT_SCSI_FC_SG_DEPTH;
4348 } else {
4349 if (numSGE > MPT_SCSI_SG_DEPTH)
4350 numSGE = MPT_SCSI_SG_DEPTH;
4351 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352
4353 num_chain = 1;
4354 while (numSGE - num_sge > 0) {
4355 num_chain++;
4356 num_sge += (scale - 1);
4357 }
4358 num_chain++;
4359
Prakash, Sathya436ace72007-07-24 15:42:08 +05304360 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 ioc->name, numSGE, num_sge, num_chain));
4362
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004363 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 num_chain *= MPT_SCSI_CAN_QUEUE;
4365 else
4366 num_chain *= MPT_FC_CAN_QUEUE;
4367
4368 ioc->num_chain = num_chain;
4369
4370 sz = num_chain * sizeof(int);
4371 if (ioc->ChainToChain == NULL) {
4372 mem = kmalloc(sz, GFP_ATOMIC);
4373 if (mem == NULL)
4374 return -1;
4375
4376 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304377 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 ioc->name, mem, sz));
4379 } else {
4380 mem = (u8 *) ioc->ChainToChain;
4381 }
4382 memset(mem, 0xFF, sz);
4383 return num_chain;
4384}
4385
4386/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004387/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4389 * @ioc: Pointer to MPT_ADAPTER structure
4390 *
4391 * This routine allocates memory for the MPT reply and request frame
4392 * pools (if necessary), and primes the IOC reply FIFO with
4393 * reply frames.
4394 *
4395 * Returns 0 for success, non-zero for failure.
4396 */
4397static int
4398PrimeIocFifos(MPT_ADAPTER *ioc)
4399{
4400 MPT_FRAME_HDR *mf;
4401 unsigned long flags;
4402 dma_addr_t alloc_dma;
4403 u8 *mem;
4404 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304405 u64 dma_mask;
4406
4407 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408
4409 /* Prime reply FIFO... */
4410
4411 if (ioc->reply_frames == NULL) {
4412 if ( (num_chain = initChainBuffers(ioc)) < 0)
4413 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304414 /*
4415 * 1078 errata workaround for the 36GB limitation
4416 */
4417 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
4418 ioc->dma_mask > DMA_35BIT_MASK) {
4419 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4420 && !pci_set_consistent_dma_mask(ioc->pcidev,
4421 DMA_BIT_MASK(32))) {
4422 dma_mask = DMA_35BIT_MASK;
4423 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4424 "setting 35 bit addressing for "
4425 "Request/Reply/Chain and Sense Buffers\n",
4426 ioc->name));
4427 } else {
4428 /*Reseting DMA mask to 64 bit*/
4429 pci_set_dma_mask(ioc->pcidev,
4430 DMA_BIT_MASK(64));
4431 pci_set_consistent_dma_mask(ioc->pcidev,
4432 DMA_BIT_MASK(64));
4433
4434 printk(MYIOC_s_ERR_FMT
4435 "failed setting 35 bit addressing for "
4436 "Request/Reply/Chain and Sense Buffers\n",
4437 ioc->name);
4438 return -1;
4439 }
4440 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441
4442 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304443 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304445 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 ioc->name, reply_sz, reply_sz));
4447
4448 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304449 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304451 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452 ioc->name, sz, sz));
4453 total_size += sz;
4454
4455 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304456 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304458 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459 ioc->name, sz, sz, num_chain));
4460
4461 total_size += sz;
4462 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4463 if (mem == NULL) {
4464 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4465 ioc->name);
4466 goto out_fail;
4467 }
4468
Prakash, Sathya436ace72007-07-24 15:42:08 +05304469 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4471
4472 memset(mem, 0, total_size);
4473 ioc->alloc_total += total_size;
4474 ioc->alloc = mem;
4475 ioc->alloc_dma = alloc_dma;
4476 ioc->alloc_sz = total_size;
4477 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4478 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4479
Prakash, Sathya436ace72007-07-24 15:42:08 +05304480 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004481 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4482
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 alloc_dma += reply_sz;
4484 mem += reply_sz;
4485
4486 /* Request FIFO - WE manage this! */
4487
4488 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4489 ioc->req_frames_dma = alloc_dma;
4490
Prakash, Sathya436ace72007-07-24 15:42:08 +05304491 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 ioc->name, mem, (void *)(ulong)alloc_dma));
4493
4494 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4495
4496#if defined(CONFIG_MTRR) && 0
4497 /*
4498 * Enable Write Combining MTRR for IOC's memory region.
4499 * (at least as much as we can; "size and base must be
4500 * multiples of 4 kiB"
4501 */
4502 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4503 sz,
4504 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304505 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 ioc->name, ioc->req_frames_dma, sz));
4507#endif
4508
4509 for (i = 0; i < ioc->req_depth; i++) {
4510 alloc_dma += ioc->req_sz;
4511 mem += ioc->req_sz;
4512 }
4513
4514 ioc->ChainBuffer = mem;
4515 ioc->ChainBufferDMA = alloc_dma;
4516
Prakash, Sathya436ace72007-07-24 15:42:08 +05304517 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4519
4520 /* Initialize the free chain Q.
4521 */
4522
4523 INIT_LIST_HEAD(&ioc->FreeChainQ);
4524
4525 /* Post the chain buffers to the FreeChainQ.
4526 */
4527 mem = (u8 *)ioc->ChainBuffer;
4528 for (i=0; i < num_chain; i++) {
4529 mf = (MPT_FRAME_HDR *) mem;
4530 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4531 mem += ioc->req_sz;
4532 }
4533
4534 /* Initialize Request frames linked list
4535 */
4536 alloc_dma = ioc->req_frames_dma;
4537 mem = (u8 *) ioc->req_frames;
4538
4539 spin_lock_irqsave(&ioc->FreeQlock, flags);
4540 INIT_LIST_HEAD(&ioc->FreeQ);
4541 for (i = 0; i < ioc->req_depth; i++) {
4542 mf = (MPT_FRAME_HDR *) mem;
4543
4544 /* Queue REQUESTs *internally*! */
4545 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4546
4547 mem += ioc->req_sz;
4548 }
4549 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4550
4551 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4552 ioc->sense_buf_pool =
4553 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4554 if (ioc->sense_buf_pool == NULL) {
4555 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4556 ioc->name);
4557 goto out_fail;
4558 }
4559
4560 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4561 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304562 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4564
4565 }
4566
4567 /* Post Reply frames to FIFO
4568 */
4569 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304570 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4572
4573 for (i = 0; i < ioc->reply_depth; i++) {
4574 /* Write each address to the IOC! */
4575 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4576 alloc_dma += ioc->reply_sz;
4577 }
4578
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304579 if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
4580 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4581 ioc->dma_mask))
4582 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4583 "restoring 64 bit addressing\n", ioc->name));
4584
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585 return 0;
4586
4587out_fail:
Kashyap, Desai2f187862009-05-29 16:52:37 +05304588
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 if (ioc->alloc != NULL) {
4590 sz = ioc->alloc_sz;
4591 pci_free_consistent(ioc->pcidev,
4592 sz,
4593 ioc->alloc, ioc->alloc_dma);
4594 ioc->reply_frames = NULL;
4595 ioc->req_frames = NULL;
4596 ioc->alloc_total -= sz;
4597 }
4598 if (ioc->sense_buf_pool != NULL) {
4599 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4600 pci_free_consistent(ioc->pcidev,
4601 sz,
4602 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4603 ioc->sense_buf_pool = NULL;
4604 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304605
4606 if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
4607 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4608 DMA_BIT_MASK(64)))
4609 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4610 "restoring 64 bit addressing\n", ioc->name));
4611
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 return -1;
4613}
4614
4615/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4616/**
4617 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4618 * from IOC via doorbell handshake method.
4619 * @ioc: Pointer to MPT_ADAPTER structure
4620 * @reqBytes: Size of the request in bytes
4621 * @req: Pointer to MPT request frame
4622 * @replyBytes: Expected size of the reply in bytes
4623 * @u16reply: Pointer to area where reply should be written
4624 * @maxwait: Max wait time for a reply (in seconds)
4625 * @sleepFlag: Specifies whether the process can sleep
4626 *
4627 * NOTES: It is the callers responsibility to byte-swap fields in the
4628 * request which are greater than 1 byte in size. It is also the
4629 * callers responsibility to byte-swap response fields which are
4630 * greater than 1 byte in size.
4631 *
4632 * Returns 0 for success, non-zero for failure.
4633 */
4634static int
4635mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004636 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637{
4638 MPIDefaultReply_t *mptReply;
4639 int failcnt = 0;
4640 int t;
4641
4642 /*
4643 * Get ready to cache a handshake reply
4644 */
4645 ioc->hs_reply_idx = 0;
4646 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4647 mptReply->MsgLength = 0;
4648
4649 /*
4650 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4651 * then tell IOC that we want to handshake a request of N words.
4652 * (WRITE u32val to Doorbell reg).
4653 */
4654 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4655 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4656 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4657 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4658
4659 /*
4660 * Wait for IOC's doorbell handshake int
4661 */
4662 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4663 failcnt++;
4664
Prakash, Sathya436ace72007-07-24 15:42:08 +05304665 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4667
4668 /* Read doorbell and check for active bit */
4669 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4670 return -1;
4671
4672 /*
4673 * Clear doorbell int (WRITE 0 to IntStatus reg),
4674 * then wait for IOC to ACKnowledge that it's ready for
4675 * our handshake request.
4676 */
4677 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4678 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4679 failcnt++;
4680
4681 if (!failcnt) {
4682 int ii;
4683 u8 *req_as_bytes = (u8 *) req;
4684
4685 /*
4686 * Stuff request words via doorbell handshake,
4687 * with ACK from IOC for each.
4688 */
4689 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4690 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4691 (req_as_bytes[(ii*4) + 1] << 8) |
4692 (req_as_bytes[(ii*4) + 2] << 16) |
4693 (req_as_bytes[(ii*4) + 3] << 24));
4694
4695 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4696 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4697 failcnt++;
4698 }
4699
Prakash, Sathya436ace72007-07-24 15:42:08 +05304700 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004701 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702
Prakash, Sathya436ace72007-07-24 15:42:08 +05304703 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4705
4706 /*
4707 * Wait for completion of doorbell handshake reply from the IOC
4708 */
4709 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4710 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004711
Prakash, Sathya436ace72007-07-24 15:42:08 +05304712 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4714
4715 /*
4716 * Copy out the cached reply...
4717 */
4718 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4719 u16reply[ii] = ioc->hs_reply[ii];
4720 } else {
4721 return -99;
4722 }
4723
4724 return -failcnt;
4725}
4726
4727/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004728/**
4729 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730 * @ioc: Pointer to MPT_ADAPTER structure
4731 * @howlong: How long to wait (in seconds)
4732 * @sleepFlag: Specifies whether the process can sleep
4733 *
4734 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004735 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4736 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737 *
4738 * Returns a negative value on failure, else wait loop count.
4739 */
4740static int
4741WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4742{
4743 int cntdn;
4744 int count = 0;
4745 u32 intstat=0;
4746
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004747 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748
4749 if (sleepFlag == CAN_SLEEP) {
4750 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004751 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4753 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4754 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 count++;
4756 }
4757 } else {
4758 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004759 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4761 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4762 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 count++;
4764 }
4765 }
4766
4767 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304768 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 ioc->name, count));
4770 return count;
4771 }
4772
4773 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4774 ioc->name, count, intstat);
4775 return -1;
4776}
4777
4778/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004779/**
4780 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 * @ioc: Pointer to MPT_ADAPTER structure
4782 * @howlong: How long to wait (in seconds)
4783 * @sleepFlag: Specifies whether the process can sleep
4784 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004785 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4786 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004787 *
4788 * Returns a negative value on failure, else wait loop count.
4789 */
4790static int
4791WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4792{
4793 int cntdn;
4794 int count = 0;
4795 u32 intstat=0;
4796
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004797 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798 if (sleepFlag == CAN_SLEEP) {
4799 while (--cntdn) {
4800 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4801 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4802 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004803 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804 count++;
4805 }
4806 } else {
4807 while (--cntdn) {
4808 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4809 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4810 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004811 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 count++;
4813 }
4814 }
4815
4816 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304817 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 ioc->name, count, howlong));
4819 return count;
4820 }
4821
4822 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4823 ioc->name, count, intstat);
4824 return -1;
4825}
4826
4827/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004828/**
4829 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830 * @ioc: Pointer to MPT_ADAPTER structure
4831 * @howlong: How long to wait (in seconds)
4832 * @sleepFlag: Specifies whether the process can sleep
4833 *
4834 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4835 * Reply is cached to IOC private area large enough to hold a maximum
4836 * of 128 bytes of reply data.
4837 *
4838 * Returns a negative value on failure, else size of reply in WORDS.
4839 */
4840static int
4841WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4842{
4843 int u16cnt = 0;
4844 int failcnt = 0;
4845 int t;
4846 u16 *hs_reply = ioc->hs_reply;
4847 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4848 u16 hword;
4849
4850 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4851
4852 /*
4853 * Get first two u16's so we can look at IOC's intended reply MsgLength
4854 */
4855 u16cnt=0;
4856 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4857 failcnt++;
4858 } else {
4859 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4860 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4861 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4862 failcnt++;
4863 else {
4864 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4865 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4866 }
4867 }
4868
Prakash, Sathya436ace72007-07-24 15:42:08 +05304869 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004870 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4872
4873 /*
4874 * If no error (and IOC said MsgLength is > 0), piece together
4875 * reply 16 bits at a time.
4876 */
4877 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4878 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4879 failcnt++;
4880 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4881 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004882 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 hs_reply[u16cnt] = hword;
4884 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4885 }
4886
4887 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4888 failcnt++;
4889 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4890
4891 if (failcnt) {
4892 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4893 ioc->name);
4894 return -failcnt;
4895 }
4896#if 0
4897 else if (u16cnt != (2 * mptReply->MsgLength)) {
4898 return -101;
4899 }
4900 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4901 return -102;
4902 }
4903#endif
4904
Prakash, Sathya436ace72007-07-24 15:42:08 +05304905 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004906 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004907
Prakash, Sathya436ace72007-07-24 15:42:08 +05304908 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909 ioc->name, t, u16cnt/2));
4910 return u16cnt/2;
4911}
4912
4913/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004914/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915 * GetLanConfigPages - Fetch LANConfig pages.
4916 * @ioc: Pointer to MPT_ADAPTER structure
4917 *
4918 * Return: 0 for success
4919 * -ENOMEM if no memory available
4920 * -EPERM if not allowed due to ISR context
4921 * -EAGAIN if no msg frames currently available
4922 * -EFAULT for non-successful reply or no reply (timeout)
4923 */
4924static int
4925GetLanConfigPages(MPT_ADAPTER *ioc)
4926{
4927 ConfigPageHeader_t hdr;
4928 CONFIGPARMS cfg;
4929 LANPage0_t *ppage0_alloc;
4930 dma_addr_t page0_dma;
4931 LANPage1_t *ppage1_alloc;
4932 dma_addr_t page1_dma;
4933 int rc = 0;
4934 int data_sz;
4935 int copy_sz;
4936
4937 /* Get LAN Page 0 header */
4938 hdr.PageVersion = 0;
4939 hdr.PageLength = 0;
4940 hdr.PageNumber = 0;
4941 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004942 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943 cfg.physAddr = -1;
4944 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4945 cfg.dir = 0;
4946 cfg.pageAddr = 0;
4947 cfg.timeout = 0;
4948
4949 if ((rc = mpt_config(ioc, &cfg)) != 0)
4950 return rc;
4951
4952 if (hdr.PageLength > 0) {
4953 data_sz = hdr.PageLength * 4;
4954 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4955 rc = -ENOMEM;
4956 if (ppage0_alloc) {
4957 memset((u8 *)ppage0_alloc, 0, data_sz);
4958 cfg.physAddr = page0_dma;
4959 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4960
4961 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4962 /* save the data */
4963 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4964 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4965
4966 }
4967
4968 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4969
4970 /* FIXME!
4971 * Normalize endianness of structure data,
4972 * by byte-swapping all > 1 byte fields!
4973 */
4974
4975 }
4976
4977 if (rc)
4978 return rc;
4979 }
4980
4981 /* Get LAN Page 1 header */
4982 hdr.PageVersion = 0;
4983 hdr.PageLength = 0;
4984 hdr.PageNumber = 1;
4985 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004986 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987 cfg.physAddr = -1;
4988 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4989 cfg.dir = 0;
4990 cfg.pageAddr = 0;
4991
4992 if ((rc = mpt_config(ioc, &cfg)) != 0)
4993 return rc;
4994
4995 if (hdr.PageLength == 0)
4996 return 0;
4997
4998 data_sz = hdr.PageLength * 4;
4999 rc = -ENOMEM;
5000 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
5001 if (ppage1_alloc) {
5002 memset((u8 *)ppage1_alloc, 0, data_sz);
5003 cfg.physAddr = page1_dma;
5004 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5005
5006 if ((rc = mpt_config(ioc, &cfg)) == 0) {
5007 /* save the data */
5008 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
5009 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
5010 }
5011
5012 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
5013
5014 /* FIXME!
5015 * Normalize endianness of structure data,
5016 * by byte-swapping all > 1 byte fields!
5017 */
5018
5019 }
5020
5021 return rc;
5022}
5023
5024/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005025/**
5026 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005027 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005028 * @persist_opcode: see below
5029 *
5030 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
5031 * devices not currently present.
5032 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
5033 *
5034 * NOTE: Don't use not this function during interrupt time.
5035 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005036 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005037 */
5038
5039/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5040int
5041mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
5042{
5043 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
5044 SasIoUnitControlReply_t *sasIoUnitCntrReply;
5045 MPT_FRAME_HDR *mf = NULL;
5046 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305047 int ret = 0;
5048 unsigned long timeleft;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005049
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305050 mutex_lock(&ioc->mptbase_cmds.mutex);
5051
5052 /* init the internal cmd struct */
5053 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
5054 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005055
5056 /* insure garbage is not sent to fw */
5057 switch(persist_opcode) {
5058
5059 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
5060 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
5061 break;
5062
5063 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305064 ret = -1;
5065 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005066 }
5067
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305068 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
5069 __func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005070
5071 /* Get a MF for this command.
5072 */
5073 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305074 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
5075 ret = -1;
5076 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005077 }
5078
5079 mpi_hdr = (MPIHeader_t *) mf;
5080 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
5081 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
5082 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
5083 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
5084 sasIoUnitCntrReq->Operation = persist_opcode;
5085
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005086 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305087 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
5088 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
5089 ret = -ETIME;
5090 printk(KERN_DEBUG "%s: failed\n", __func__);
5091 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
5092 goto out;
5093 if (!timeleft) {
5094 printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n",
5095 ioc->name, __func__);
5096 mpt_HardResetHandler(ioc, CAN_SLEEP);
5097 mpt_free_msg_frame(ioc, mf);
5098 }
5099 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005100 }
5101
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305102 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
5103 ret = -1;
5104 goto out;
5105 }
5106
5107 sasIoUnitCntrReply =
5108 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5109 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5110 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5111 __func__, sasIoUnitCntrReply->IOCStatus,
5112 sasIoUnitCntrReply->IOCLogInfo);
5113 printk(KERN_DEBUG "%s: failed\n", __func__);
5114 ret = -1;
5115 } else
5116 printk(KERN_DEBUG "%s: success\n", __func__);
5117 out:
5118
5119 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5120 mutex_unlock(&ioc->mptbase_cmds.mutex);
5121 return ret;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005122}
5123
5124/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005125
5126static void
5127mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5128 MpiEventDataRaid_t * pRaidEventData)
5129{
5130 int volume;
5131 int reason;
5132 int disk;
5133 int status;
5134 int flags;
5135 int state;
5136
5137 volume = pRaidEventData->VolumeID;
5138 reason = pRaidEventData->ReasonCode;
5139 disk = pRaidEventData->PhysDiskNum;
5140 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5141 flags = (status >> 0) & 0xff;
5142 state = (status >> 8) & 0xff;
5143
5144 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5145 return;
5146 }
5147
5148 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5149 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5150 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005151 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5152 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005153 } else {
5154 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5155 ioc->name, volume);
5156 }
5157
5158 switch(reason) {
5159 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5160 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5161 ioc->name);
5162 break;
5163
5164 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5165
5166 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5167 ioc->name);
5168 break;
5169
5170 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5171 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5172 ioc->name);
5173 break;
5174
5175 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5176 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5177 ioc->name,
5178 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5179 ? "optimal"
5180 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5181 ? "degraded"
5182 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5183 ? "failed"
5184 : "state unknown",
5185 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5186 ? ", enabled" : "",
5187 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5188 ? ", quiesced" : "",
5189 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5190 ? ", resync in progress" : "" );
5191 break;
5192
5193 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5194 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5195 ioc->name, disk);
5196 break;
5197
5198 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5199 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5200 ioc->name);
5201 break;
5202
5203 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5204 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5205 ioc->name);
5206 break;
5207
5208 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5209 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5210 ioc->name);
5211 break;
5212
5213 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5214 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5215 ioc->name,
5216 state == MPI_PHYSDISK0_STATUS_ONLINE
5217 ? "online"
5218 : state == MPI_PHYSDISK0_STATUS_MISSING
5219 ? "missing"
5220 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5221 ? "not compatible"
5222 : state == MPI_PHYSDISK0_STATUS_FAILED
5223 ? "failed"
5224 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5225 ? "initializing"
5226 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5227 ? "offline requested"
5228 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5229 ? "failed requested"
5230 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5231 ? "offline"
5232 : "state unknown",
5233 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5234 ? ", out of sync" : "",
5235 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5236 ? ", quiesced" : "" );
5237 break;
5238
5239 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5240 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5241 ioc->name, disk);
5242 break;
5243
5244 case MPI_EVENT_RAID_RC_SMART_DATA:
5245 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5246 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5247 break;
5248
5249 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5250 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5251 ioc->name, disk);
5252 break;
5253 }
5254}
5255
5256/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005257/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005258 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5259 * @ioc: Pointer to MPT_ADAPTER structure
5260 *
5261 * Returns: 0 for success
5262 * -ENOMEM if no memory available
5263 * -EPERM if not allowed due to ISR context
5264 * -EAGAIN if no msg frames currently available
5265 * -EFAULT for non-successful reply or no reply (timeout)
5266 */
5267static int
5268GetIoUnitPage2(MPT_ADAPTER *ioc)
5269{
5270 ConfigPageHeader_t hdr;
5271 CONFIGPARMS cfg;
5272 IOUnitPage2_t *ppage_alloc;
5273 dma_addr_t page_dma;
5274 int data_sz;
5275 int rc;
5276
5277 /* Get the page header */
5278 hdr.PageVersion = 0;
5279 hdr.PageLength = 0;
5280 hdr.PageNumber = 2;
5281 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005282 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283 cfg.physAddr = -1;
5284 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5285 cfg.dir = 0;
5286 cfg.pageAddr = 0;
5287 cfg.timeout = 0;
5288
5289 if ((rc = mpt_config(ioc, &cfg)) != 0)
5290 return rc;
5291
5292 if (hdr.PageLength == 0)
5293 return 0;
5294
5295 /* Read the config page */
5296 data_sz = hdr.PageLength * 4;
5297 rc = -ENOMEM;
5298 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5299 if (ppage_alloc) {
5300 memset((u8 *)ppage_alloc, 0, data_sz);
5301 cfg.physAddr = page_dma;
5302 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5303
5304 /* If Good, save data */
5305 if ((rc = mpt_config(ioc, &cfg)) == 0)
5306 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5307
5308 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5309 }
5310
5311 return rc;
5312}
5313
5314/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005315/**
5316 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005317 * @ioc: Pointer to a Adapter Strucutre
5318 * @portnum: IOC port number
5319 *
5320 * Return: -EFAULT if read of config page header fails
5321 * or if no nvram
5322 * If read of SCSI Port Page 0 fails,
5323 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5324 * Adapter settings: async, narrow
5325 * Return 1
5326 * If read of SCSI Port Page 2 fails,
5327 * Adapter settings valid
5328 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5329 * Return 1
5330 * Else
5331 * Both valid
5332 * Return 0
5333 * CHECK - what type of locking mechanisms should be used????
5334 */
5335static int
5336mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5337{
5338 u8 *pbuf;
5339 dma_addr_t buf_dma;
5340 CONFIGPARMS cfg;
5341 ConfigPageHeader_t header;
5342 int ii;
5343 int data, rc = 0;
5344
5345 /* Allocate memory
5346 */
5347 if (!ioc->spi_data.nvram) {
5348 int sz;
5349 u8 *mem;
5350 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5351 mem = kmalloc(sz, GFP_ATOMIC);
5352 if (mem == NULL)
5353 return -EFAULT;
5354
5355 ioc->spi_data.nvram = (int *) mem;
5356
Prakash, Sathya436ace72007-07-24 15:42:08 +05305357 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358 ioc->name, ioc->spi_data.nvram, sz));
5359 }
5360
5361 /* Invalidate NVRAM information
5362 */
5363 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5364 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5365 }
5366
5367 /* Read SPP0 header, allocate memory, then read page.
5368 */
5369 header.PageVersion = 0;
5370 header.PageLength = 0;
5371 header.PageNumber = 0;
5372 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005373 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005374 cfg.physAddr = -1;
5375 cfg.pageAddr = portnum;
5376 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5377 cfg.dir = 0;
5378 cfg.timeout = 0; /* use default */
5379 if (mpt_config(ioc, &cfg) != 0)
5380 return -EFAULT;
5381
5382 if (header.PageLength > 0) {
5383 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5384 if (pbuf) {
5385 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5386 cfg.physAddr = buf_dma;
5387 if (mpt_config(ioc, &cfg) != 0) {
5388 ioc->spi_data.maxBusWidth = MPT_NARROW;
5389 ioc->spi_data.maxSyncOffset = 0;
5390 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5391 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5392 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305393 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5394 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005395 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396 } else {
5397 /* Save the Port Page 0 data
5398 */
5399 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5400 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5401 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5402
5403 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5404 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005405 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5406 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 ioc->name, pPP0->Capabilities));
5408 }
5409 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5410 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5411 if (data) {
5412 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5413 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5414 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305415 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5416 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005417 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418 } else {
5419 ioc->spi_data.maxSyncOffset = 0;
5420 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5421 }
5422
5423 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5424
5425 /* Update the minSyncFactor based on bus type.
5426 */
5427 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5428 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5429
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005430 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305432 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5433 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005434 ioc->name, ioc->spi_data.minSyncFactor));
5435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436 }
5437 }
5438 if (pbuf) {
5439 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5440 }
5441 }
5442 }
5443
5444 /* SCSI Port Page 2 - Read the header then the page.
5445 */
5446 header.PageVersion = 0;
5447 header.PageLength = 0;
5448 header.PageNumber = 2;
5449 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005450 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451 cfg.physAddr = -1;
5452 cfg.pageAddr = portnum;
5453 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5454 cfg.dir = 0;
5455 if (mpt_config(ioc, &cfg) != 0)
5456 return -EFAULT;
5457
5458 if (header.PageLength > 0) {
5459 /* Allocate memory and read SCSI Port Page 2
5460 */
5461 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5462 if (pbuf) {
5463 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5464 cfg.physAddr = buf_dma;
5465 if (mpt_config(ioc, &cfg) != 0) {
5466 /* Nvram data is left with INVALID mark
5467 */
5468 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005469 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5470
5471 /* This is an ATTO adapter, read Page2 accordingly
5472 */
5473 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5474 ATTODeviceInfo_t *pdevice = NULL;
5475 u16 ATTOFlags;
5476
5477 /* Save the Port Page 2 data
5478 * (reformat into a 32bit quantity)
5479 */
5480 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5481 pdevice = &pPP2->DeviceSettings[ii];
5482 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5483 data = 0;
5484
5485 /* Translate ATTO device flags to LSI format
5486 */
5487 if (ATTOFlags & ATTOFLAG_DISC)
5488 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5489 if (ATTOFlags & ATTOFLAG_ID_ENB)
5490 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5491 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5492 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5493 if (ATTOFlags & ATTOFLAG_TAGGED)
5494 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5495 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5496 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5497
5498 data = (data << 16) | (pdevice->Period << 8) | 10;
5499 ioc->spi_data.nvram[ii] = data;
5500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501 } else {
5502 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5503 MpiDeviceInfo_t *pdevice = NULL;
5504
Moore, Ericd8e925d2006-01-16 18:53:06 -07005505 /*
5506 * Save "Set to Avoid SCSI Bus Resets" flag
5507 */
5508 ioc->spi_data.bus_reset =
5509 (le32_to_cpu(pPP2->PortFlags) &
5510 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5511 0 : 1 ;
5512
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 /* Save the Port Page 2 data
5514 * (reformat into a 32bit quantity)
5515 */
5516 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5517 ioc->spi_data.PortFlags = data;
5518 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5519 pdevice = &pPP2->DeviceSettings[ii];
5520 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5521 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5522 ioc->spi_data.nvram[ii] = data;
5523 }
5524 }
5525
5526 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5527 }
5528 }
5529
5530 /* Update Adapter limits with those from NVRAM
5531 * Comment: Don't need to do this. Target performance
5532 * parameters will never exceed the adapters limits.
5533 */
5534
5535 return rc;
5536}
5537
5538/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005539/**
5540 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541 * @ioc: Pointer to a Adapter Strucutre
5542 * @portnum: IOC port number
5543 *
5544 * Return: -EFAULT if read of config page header fails
5545 * or 0 if success.
5546 */
5547static int
5548mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5549{
5550 CONFIGPARMS cfg;
5551 ConfigPageHeader_t header;
5552
5553 /* Read the SCSI Device Page 1 header
5554 */
5555 header.PageVersion = 0;
5556 header.PageLength = 0;
5557 header.PageNumber = 1;
5558 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005559 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005560 cfg.physAddr = -1;
5561 cfg.pageAddr = portnum;
5562 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5563 cfg.dir = 0;
5564 cfg.timeout = 0;
5565 if (mpt_config(ioc, &cfg) != 0)
5566 return -EFAULT;
5567
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005568 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5569 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570
5571 header.PageVersion = 0;
5572 header.PageLength = 0;
5573 header.PageNumber = 0;
5574 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5575 if (mpt_config(ioc, &cfg) != 0)
5576 return -EFAULT;
5577
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005578 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5579 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580
Prakash, Sathya436ace72007-07-24 15:42:08 +05305581 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5583
Prakash, Sathya436ace72007-07-24 15:42:08 +05305584 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5586 return 0;
5587}
5588
Eric Mooreb506ade2007-01-29 09:45:37 -07005589/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005590 * mpt_inactive_raid_list_free - This clears this link list.
5591 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005592 **/
5593static void
5594mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5595{
5596 struct inactive_raid_component_info *component_info, *pNext;
5597
5598 if (list_empty(&ioc->raid_data.inactive_list))
5599 return;
5600
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005601 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005602 list_for_each_entry_safe(component_info, pNext,
5603 &ioc->raid_data.inactive_list, list) {
5604 list_del(&component_info->list);
5605 kfree(component_info);
5606 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005607 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005608}
5609
5610/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005611 * mpt_inactive_raid_volumes - sets up link list of phy_disk_nums for devices belonging in an inactive volume
Eric Mooreb506ade2007-01-29 09:45:37 -07005612 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005613 * @ioc : pointer to per adapter structure
5614 * @channel : volume channel
5615 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005616 **/
5617static void
5618mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5619{
5620 CONFIGPARMS cfg;
5621 ConfigPageHeader_t hdr;
5622 dma_addr_t dma_handle;
5623 pRaidVolumePage0_t buffer = NULL;
5624 int i;
5625 RaidPhysDiskPage0_t phys_disk;
5626 struct inactive_raid_component_info *component_info;
5627 int handle_inactive_volumes;
5628
5629 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5630 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5631 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5632 cfg.pageAddr = (channel << 8) + id;
5633 cfg.cfghdr.hdr = &hdr;
5634 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5635
5636 if (mpt_config(ioc, &cfg) != 0)
5637 goto out;
5638
5639 if (!hdr.PageLength)
5640 goto out;
5641
5642 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5643 &dma_handle);
5644
5645 if (!buffer)
5646 goto out;
5647
5648 cfg.physAddr = dma_handle;
5649 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5650
5651 if (mpt_config(ioc, &cfg) != 0)
5652 goto out;
5653
5654 if (!buffer->NumPhysDisks)
5655 goto out;
5656
5657 handle_inactive_volumes =
5658 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5659 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5660 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5661 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5662
5663 if (!handle_inactive_volumes)
5664 goto out;
5665
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005666 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005667 for (i = 0; i < buffer->NumPhysDisks; i++) {
5668 if(mpt_raid_phys_disk_pg0(ioc,
5669 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5670 continue;
5671
5672 if ((component_info = kmalloc(sizeof (*component_info),
5673 GFP_KERNEL)) == NULL)
5674 continue;
5675
5676 component_info->volumeID = id;
5677 component_info->volumeBus = channel;
5678 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5679 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5680 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5681 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5682
5683 list_add_tail(&component_info->list,
5684 &ioc->raid_data.inactive_list);
5685 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005686 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005687
5688 out:
5689 if (buffer)
5690 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5691 dma_handle);
5692}
5693
5694/**
5695 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5696 * @ioc: Pointer to a Adapter Structure
5697 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5698 * @phys_disk: requested payload data returned
5699 *
5700 * Return:
5701 * 0 on success
5702 * -EFAULT if read of config page header fails or data pointer not NULL
5703 * -ENOMEM if pci_alloc failed
5704 **/
5705int
Kashyap, Desai2f187862009-05-29 16:52:37 +05305706mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
5707 RaidPhysDiskPage0_t *phys_disk)
Eric Mooreb506ade2007-01-29 09:45:37 -07005708{
Kashyap, Desai2f187862009-05-29 16:52:37 +05305709 CONFIGPARMS cfg;
5710 ConfigPageHeader_t hdr;
Eric Mooreb506ade2007-01-29 09:45:37 -07005711 dma_addr_t dma_handle;
5712 pRaidPhysDiskPage0_t buffer = NULL;
5713 int rc;
5714
5715 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5716 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
Kashyap, Desai2f187862009-05-29 16:52:37 +05305717 memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
Eric Mooreb506ade2007-01-29 09:45:37 -07005718
Kashyap, Desai2f187862009-05-29 16:52:37 +05305719 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
Eric Mooreb506ade2007-01-29 09:45:37 -07005720 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5721 cfg.cfghdr.hdr = &hdr;
5722 cfg.physAddr = -1;
5723 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5724
5725 if (mpt_config(ioc, &cfg) != 0) {
5726 rc = -EFAULT;
5727 goto out;
5728 }
5729
5730 if (!hdr.PageLength) {
5731 rc = -EFAULT;
5732 goto out;
5733 }
5734
5735 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5736 &dma_handle);
5737
5738 if (!buffer) {
5739 rc = -ENOMEM;
5740 goto out;
5741 }
5742
5743 cfg.physAddr = dma_handle;
5744 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5745 cfg.pageAddr = phys_disk_num;
5746
5747 if (mpt_config(ioc, &cfg) != 0) {
5748 rc = -EFAULT;
5749 goto out;
5750 }
5751
5752 rc = 0;
5753 memcpy(phys_disk, buffer, sizeof(*buffer));
5754 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5755
5756 out:
5757
5758 if (buffer)
5759 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5760 dma_handle);
5761
5762 return rc;
5763}
5764
Linus Torvalds1da177e2005-04-16 15:20:36 -07005765/**
5766 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5767 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768 *
5769 * Return:
5770 * 0 on success
5771 * -EFAULT if read of config page header fails or data pointer not NULL
5772 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005773 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005774int
5775mpt_findImVolumes(MPT_ADAPTER *ioc)
5776{
5777 IOCPage2_t *pIoc2;
5778 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005779 dma_addr_t ioc2_dma;
5780 CONFIGPARMS cfg;
5781 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782 int rc = 0;
5783 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005784 int i;
5785
5786 if (!ioc->ir_firmware)
5787 return 0;
5788
5789 /* Free the old page
5790 */
5791 kfree(ioc->raid_data.pIocPg2);
5792 ioc->raid_data.pIocPg2 = NULL;
5793 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005794
5795 /* Read IOCP2 header then the page.
5796 */
5797 header.PageVersion = 0;
5798 header.PageLength = 0;
5799 header.PageNumber = 2;
5800 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005801 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802 cfg.physAddr = -1;
5803 cfg.pageAddr = 0;
5804 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5805 cfg.dir = 0;
5806 cfg.timeout = 0;
5807 if (mpt_config(ioc, &cfg) != 0)
5808 return -EFAULT;
5809
5810 if (header.PageLength == 0)
5811 return -EFAULT;
5812
5813 iocpage2sz = header.PageLength * 4;
5814 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5815 if (!pIoc2)
5816 return -ENOMEM;
5817
5818 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5819 cfg.physAddr = ioc2_dma;
5820 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005821 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822
Eric Mooreb506ade2007-01-29 09:45:37 -07005823 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5824 if (!mem)
5825 goto out;
5826
Linus Torvalds1da177e2005-04-16 15:20:36 -07005827 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005828 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005829
Eric Mooreb506ade2007-01-29 09:45:37 -07005830 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005831
Eric Mooreb506ade2007-01-29 09:45:37 -07005832 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5833 mpt_inactive_raid_volumes(ioc,
5834 pIoc2->RaidVolume[i].VolumeBus,
5835 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005836
Eric Mooreb506ade2007-01-29 09:45:37 -07005837 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005838 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5839
5840 return rc;
5841}
5842
Moore, Ericc972c702006-03-14 09:14:06 -07005843static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005844mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5845{
5846 IOCPage3_t *pIoc3;
5847 u8 *mem;
5848 CONFIGPARMS cfg;
5849 ConfigPageHeader_t header;
5850 dma_addr_t ioc3_dma;
5851 int iocpage3sz = 0;
5852
5853 /* Free the old page
5854 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005855 kfree(ioc->raid_data.pIocPg3);
5856 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005857
5858 /* There is at least one physical disk.
5859 * Read and save IOC Page 3
5860 */
5861 header.PageVersion = 0;
5862 header.PageLength = 0;
5863 header.PageNumber = 3;
5864 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005865 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866 cfg.physAddr = -1;
5867 cfg.pageAddr = 0;
5868 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5869 cfg.dir = 0;
5870 cfg.timeout = 0;
5871 if (mpt_config(ioc, &cfg) != 0)
5872 return 0;
5873
5874 if (header.PageLength == 0)
5875 return 0;
5876
5877 /* Read Header good, alloc memory
5878 */
5879 iocpage3sz = header.PageLength * 4;
5880 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5881 if (!pIoc3)
5882 return 0;
5883
5884 /* Read the Page and save the data
5885 * into malloc'd memory.
5886 */
5887 cfg.physAddr = ioc3_dma;
5888 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5889 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005890 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891 if (mem) {
5892 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005893 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005894 }
5895 }
5896
5897 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5898
5899 return 0;
5900}
5901
5902static void
5903mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5904{
5905 IOCPage4_t *pIoc4;
5906 CONFIGPARMS cfg;
5907 ConfigPageHeader_t header;
5908 dma_addr_t ioc4_dma;
5909 int iocpage4sz;
5910
5911 /* Read and save IOC Page 4
5912 */
5913 header.PageVersion = 0;
5914 header.PageLength = 0;
5915 header.PageNumber = 4;
5916 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005917 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005918 cfg.physAddr = -1;
5919 cfg.pageAddr = 0;
5920 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5921 cfg.dir = 0;
5922 cfg.timeout = 0;
5923 if (mpt_config(ioc, &cfg) != 0)
5924 return;
5925
5926 if (header.PageLength == 0)
5927 return;
5928
5929 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5930 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5931 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5932 if (!pIoc4)
5933 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005934 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005935 } else {
5936 ioc4_dma = ioc->spi_data.IocPg4_dma;
5937 iocpage4sz = ioc->spi_data.IocPg4Sz;
5938 }
5939
5940 /* Read the Page into dma memory.
5941 */
5942 cfg.physAddr = ioc4_dma;
5943 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5944 if (mpt_config(ioc, &cfg) == 0) {
5945 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5946 ioc->spi_data.IocPg4_dma = ioc4_dma;
5947 ioc->spi_data.IocPg4Sz = iocpage4sz;
5948 } else {
5949 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5950 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005951 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005952 }
5953}
5954
5955static void
5956mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5957{
5958 IOCPage1_t *pIoc1;
5959 CONFIGPARMS cfg;
5960 ConfigPageHeader_t header;
5961 dma_addr_t ioc1_dma;
5962 int iocpage1sz = 0;
5963 u32 tmp;
5964
5965 /* Check the Coalescing Timeout in IOC Page 1
5966 */
5967 header.PageVersion = 0;
5968 header.PageLength = 0;
5969 header.PageNumber = 1;
5970 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005971 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005972 cfg.physAddr = -1;
5973 cfg.pageAddr = 0;
5974 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5975 cfg.dir = 0;
5976 cfg.timeout = 0;
5977 if (mpt_config(ioc, &cfg) != 0)
5978 return;
5979
5980 if (header.PageLength == 0)
5981 return;
5982
5983 /* Read Header good, alloc memory
5984 */
5985 iocpage1sz = header.PageLength * 4;
5986 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5987 if (!pIoc1)
5988 return;
5989
5990 /* Read the Page and check coalescing timeout
5991 */
5992 cfg.physAddr = ioc1_dma;
5993 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5994 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305995
Linus Torvalds1da177e2005-04-16 15:20:36 -07005996 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5997 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5998 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5999
Prakash, Sathya436ace72007-07-24 15:42:08 +05306000 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006001 ioc->name, tmp));
6002
6003 if (tmp > MPT_COALESCING_TIMEOUT) {
6004 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
6005
6006 /* Write NVRAM and current
6007 */
6008 cfg.dir = 1;
6009 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
6010 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306011 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006012 ioc->name, MPT_COALESCING_TIMEOUT));
6013
6014 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
6015 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306016 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6017 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006018 ioc->name, MPT_COALESCING_TIMEOUT));
6019 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306020 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6021 "Reset NVRAM Coalescing Timeout Failed\n",
6022 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006023 }
6024
6025 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306026 dprintk(ioc, printk(MYIOC_s_WARN_FMT
6027 "Reset of Current Coalescing Timeout Failed!\n",
6028 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006029 }
6030 }
6031
6032 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306033 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006034 }
6035 }
6036
6037 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
6038
6039 return;
6040}
6041
Prakash, Sathyaedb90682007-07-17 14:39:14 +05306042static void
6043mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
6044{
6045 CONFIGPARMS cfg;
6046 ConfigPageHeader_t hdr;
6047 dma_addr_t buf_dma;
6048 ManufacturingPage0_t *pbuf = NULL;
6049
6050 memset(&cfg, 0 , sizeof(CONFIGPARMS));
6051 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
6052
6053 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
6054 cfg.cfghdr.hdr = &hdr;
6055 cfg.physAddr = -1;
6056 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6057 cfg.timeout = 10;
6058
6059 if (mpt_config(ioc, &cfg) != 0)
6060 goto out;
6061
6062 if (!cfg.cfghdr.hdr->PageLength)
6063 goto out;
6064
6065 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6066 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
6067 if (!pbuf)
6068 goto out;
6069
6070 cfg.physAddr = buf_dma;
6071
6072 if (mpt_config(ioc, &cfg) != 0)
6073 goto out;
6074
6075 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
6076 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
6077 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
6078
6079 out:
6080
6081 if (pbuf)
6082 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
6083}
6084
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006086/**
6087 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006088 * @ioc: Pointer to MPT_ADAPTER structure
6089 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05306090 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07006091 */
6092static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05306093SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006094{
Kashyap, Desaifd761752009-05-29 16:39:06 +05306095 EventNotification_t evn;
6096 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006097
Kashyap, Desaifd761752009-05-29 16:39:06 +05306098 memset(&evn, 0, sizeof(EventNotification_t));
6099 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006100
Kashyap, Desaifd761752009-05-29 16:39:06 +05306101 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
6102 evn.Switch = EvSwitch;
6103 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006104
Kashyap, Desaifd761752009-05-29 16:39:06 +05306105 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6106 "Sending EventNotification (%d) request %p\n",
6107 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006108
Kashyap, Desaifd761752009-05-29 16:39:06 +05306109 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6110 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6111 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006112}
6113
6114/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6115/**
6116 * SendEventAck - Send EventAck request to MPT adapter.
6117 * @ioc: Pointer to MPT_ADAPTER structure
6118 * @evnp: Pointer to original EventNotification request
6119 */
6120static int
6121SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6122{
6123 EventAck_t *pAck;
6124
6125 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306126 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306127 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006128 return -1;
6129 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006130
Prakash, Sathya436ace72007-07-24 15:42:08 +05306131 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006132
6133 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6134 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006135 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006136 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006137 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006138 pAck->Event = evnp->Event;
6139 pAck->EventContext = evnp->EventContext;
6140
6141 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6142
6143 return 0;
6144}
6145
6146/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6147/**
6148 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006149 * @ioc: Pointer to an adapter structure
6150 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006151 * action, page address, direction, physical address
6152 * and pointer to a configuration page header
6153 * Page header is updated.
6154 *
6155 * Returns 0 for success
6156 * -EPERM if not allowed due to ISR context
6157 * -EAGAIN if no msg frames currently available
6158 * -EFAULT for non-successful reply or no reply (timeout)
6159 */
6160int
6161mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6162{
6163 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306164 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006165 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006166 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306167 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006168 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306169 long timeout;
6170 int ret;
6171 u8 page_type = 0, extend_page;
6172 unsigned long timeleft;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306173 unsigned long flags;
6174 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306175 u8 issue_hard_reset = 0;
6176 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006177
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006178 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006179 * to be in ISR context, because that is fatal!
6180 */
6181 in_isr = in_interrupt();
6182 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306183 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006184 ioc->name));
6185 return -EPERM;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306186 }
6187
6188 /* don't send a config page during diag reset */
6189 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6190 if (ioc->ioc_reset_in_progress) {
6191 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6192 "%s: busy with host reset\n", ioc->name, __func__));
6193 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6194 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006195 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306196 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006197
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306198 /* don't send if no chance of success */
6199 if (!ioc->active ||
6200 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6201 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6202 "%s: ioc not operational, %d, %xh\n",
6203 ioc->name, __func__, ioc->active,
6204 mpt_GetIocState(ioc, 0)));
6205 return -EFAULT;
6206 }
6207
6208 retry_config:
6209 mutex_lock(&ioc->mptbase_cmds.mutex);
6210 /* init the internal cmd struct */
6211 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6212 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6213
Linus Torvalds1da177e2005-04-16 15:20:36 -07006214 /* Get and Populate a free Frame
6215 */
6216 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306217 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6218 "mpt_config: no msg frames!\n", ioc->name));
6219 ret = -EAGAIN;
6220 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006221 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306222
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223 pReq = (Config_t *)mf;
6224 pReq->Action = pCfg->action;
6225 pReq->Reserved = 0;
6226 pReq->ChainOffset = 0;
6227 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006228
6229 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006230 pReq->ExtPageLength = 0;
6231 pReq->ExtPageType = 0;
6232 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006233
Linus Torvalds1da177e2005-04-16 15:20:36 -07006234 for (ii=0; ii < 8; ii++)
6235 pReq->Reserved2[ii] = 0;
6236
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006237 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6238 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6239 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6240 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6241
6242 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6243 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6244 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6245 pReq->ExtPageType = pExtHdr->ExtPageType;
6246 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6247
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306248 /* Page Length must be treated as a reserved field for the
6249 * extended header.
6250 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006251 pReq->Header.PageLength = 0;
6252 }
6253
Linus Torvalds1da177e2005-04-16 15:20:36 -07006254 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6255
6256 /* Add a SGE to the config request.
6257 */
6258 if (pCfg->dir)
6259 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6260 else
6261 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6262
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306263 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6264 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006265 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306266 page_type = pReq->ExtPageType;
6267 extend_page = 1;
6268 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006269 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306270 page_type = pReq->Header.PageType;
6271 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006272 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006273
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306274 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6275 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6276 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6277
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306278 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306279 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006280 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306281 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6282 timeout);
6283 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6284 ret = -ETIME;
6285 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6286 "Failed Sending Config request type 0x%x, page 0x%x,"
6287 " action %d, status %xh, time left %ld\n\n",
6288 ioc->name, page_type, pReq->Header.PageNumber,
6289 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6290 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6291 goto out;
6292 if (!timeleft)
6293 issue_hard_reset = 1;
6294 goto out;
6295 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006296
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306297 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6298 ret = -1;
6299 goto out;
6300 }
6301 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6302 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6303 if (ret == MPI_IOCSTATUS_SUCCESS) {
6304 if (extend_page) {
6305 pCfg->cfghdr.ehdr->ExtPageLength =
6306 le16_to_cpu(pReply->ExtPageLength);
6307 pCfg->cfghdr.ehdr->ExtPageType =
6308 pReply->ExtPageType;
6309 }
6310 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6311 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6312 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6313 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006314
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306315 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006316
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306317 if (retry_count)
6318 printk(MYIOC_s_INFO_FMT "Retry completed "
6319 "ret=0x%x timeleft=%ld\n",
6320 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006321
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306322 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6323 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006324
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306325out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006326
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306327 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6328 mutex_unlock(&ioc->mptbase_cmds.mutex);
6329 if (issue_hard_reset) {
6330 issue_hard_reset = 0;
6331 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
6332 ioc->name, __func__);
6333 mpt_HardResetHandler(ioc, CAN_SLEEP);
6334 mpt_free_msg_frame(ioc, mf);
6335 /* attempt one retry for a timed out command */
6336 if (!retry_count) {
6337 printk(MYIOC_s_INFO_FMT
6338 "Attempting Retry Config request"
6339 " type 0x%x, page 0x%x,"
6340 " action %d\n", ioc->name, page_type,
6341 pCfg->cfghdr.hdr->PageNumber, pCfg->action);
6342 retry_count++;
6343 goto retry_config;
6344 }
6345 }
6346 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006347
Linus Torvalds1da177e2005-04-16 15:20:36 -07006348}
6349
6350/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006351/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006352 * mpt_ioc_reset - Base cleanup for hard reset
6353 * @ioc: Pointer to the adapter structure
6354 * @reset_phase: Indicates pre- or post-reset functionality
6355 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006356 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006357 */
6358static int
6359mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6360{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306361 switch (reset_phase) {
6362 case MPT_IOC_SETUP_RESET:
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306363 ioc->taskmgmt_quiesce_io = 1;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306364 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6365 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
6366 break;
6367 case MPT_IOC_PRE_RESET:
6368 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6369 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
6370 break;
6371 case MPT_IOC_POST_RESET:
6372 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6373 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
6374/* wake up mptbase_cmds */
6375 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6376 ioc->mptbase_cmds.status |=
6377 MPT_MGMT_STATUS_DID_IOCRESET;
6378 complete(&ioc->mptbase_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006379 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306380/* wake up taskmgmt_cmds */
6381 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
6382 ioc->taskmgmt_cmds.status |=
6383 MPT_MGMT_STATUS_DID_IOCRESET;
6384 complete(&ioc->taskmgmt_cmds.done);
6385 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306386 break;
6387 default:
6388 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006389 }
6390
6391 return 1; /* currently means nothing really */
6392}
6393
6394
6395#ifdef CONFIG_PROC_FS /* { */
6396/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6397/*
6398 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6399 */
6400/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006401/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006402 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6403 *
6404 * Returns 0 for success, non-zero for failure.
6405 */
6406static int
6407procmpt_create(void)
6408{
6409 struct proc_dir_entry *ent;
6410
6411 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6412 if (mpt_proc_root_dir == NULL)
6413 return -ENOTDIR;
6414
6415 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6416 if (ent)
6417 ent->read_proc = procmpt_summary_read;
6418
6419 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6420 if (ent)
6421 ent->read_proc = procmpt_version_read;
6422
6423 return 0;
6424}
6425
6426/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006427/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006428 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6429 *
6430 * Returns 0 for success, non-zero for failure.
6431 */
6432static void
6433procmpt_destroy(void)
6434{
6435 remove_proc_entry("version", mpt_proc_root_dir);
6436 remove_proc_entry("summary", mpt_proc_root_dir);
6437 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6438}
6439
6440/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006441/**
6442 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006443 * @buf: Pointer to area to write information
6444 * @start: Pointer to start pointer
6445 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006446 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006447 * @eof: Pointer to EOF integer
6448 * @data: Pointer
6449 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006450 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006451 * Returns number of characters written to process performing the read.
6452 */
6453static int
6454procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6455{
6456 MPT_ADAPTER *ioc;
6457 char *out = buf;
6458 int len;
6459
6460 if (data) {
6461 int more = 0;
6462
6463 ioc = data;
6464 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6465
6466 out += more;
6467 } else {
6468 list_for_each_entry(ioc, &ioc_list, list) {
6469 int more = 0;
6470
6471 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6472
6473 out += more;
6474 if ((out-buf) >= request)
6475 break;
6476 }
6477 }
6478
6479 len = out - buf;
6480
6481 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6482}
6483
6484/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006485/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006486 * procmpt_version_read - Handle read request from /proc/mpt/version.
6487 * @buf: Pointer to area to write information
6488 * @start: Pointer to start pointer
6489 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006490 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006491 * @eof: Pointer to EOF integer
6492 * @data: Pointer
6493 *
6494 * Returns number of characters written to process performing the read.
6495 */
6496static int
6497procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6498{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306499 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006500 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006501 char *drvname;
6502 int len;
6503
6504 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6505 len += sprintf(buf+len, " Fusion MPT base driver\n");
6506
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006507 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006508 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006509 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306510 if (MptCallbacks[cb_idx]) {
6511 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006512 case MPTSPI_DRIVER:
6513 if (!scsi++) drvname = "SPI host";
6514 break;
6515 case MPTFC_DRIVER:
6516 if (!fc++) drvname = "FC host";
6517 break;
6518 case MPTSAS_DRIVER:
6519 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006520 break;
6521 case MPTLAN_DRIVER:
6522 if (!lan++) drvname = "LAN";
6523 break;
6524 case MPTSTM_DRIVER:
6525 if (!targ++) drvname = "SCSI target";
6526 break;
6527 case MPTCTL_DRIVER:
6528 if (!ctl++) drvname = "ioctl";
6529 break;
6530 }
6531
6532 if (drvname)
6533 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6534 }
6535 }
6536
6537 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6538}
6539
6540/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006541/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006542 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6543 * @buf: Pointer to area to write information
6544 * @start: Pointer to start pointer
6545 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006546 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006547 * @eof: Pointer to EOF integer
6548 * @data: Pointer
6549 *
6550 * Returns number of characters written to process performing the read.
6551 */
6552static int
6553procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6554{
6555 MPT_ADAPTER *ioc = data;
6556 int len;
6557 char expVer[32];
6558 int sz;
6559 int p;
6560
6561 mpt_get_fw_exp_ver(expVer, ioc);
6562
6563 len = sprintf(buf, "%s:", ioc->name);
6564 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6565 len += sprintf(buf+len, " (f/w download boot flag set)");
6566// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6567// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6568
6569 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6570 ioc->facts.ProductID,
6571 ioc->prod_name);
6572 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6573 if (ioc->facts.FWImageSize)
6574 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6575 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6576 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6577 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6578
6579 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6580 ioc->facts.CurrentHostMfaHighAddr);
6581 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6582 ioc->facts.CurrentSenseBufferHighAddr);
6583
6584 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6585 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6586
6587 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6588 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6589 /*
6590 * Rounding UP to nearest 4-kB boundary here...
6591 */
6592 sz = (ioc->req_sz * ioc->req_depth) + 128;
6593 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6594 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6595 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6596 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6597 4*ioc->facts.RequestFrameSize,
6598 ioc->facts.GlobalCredits);
6599
6600 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6601 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6602 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6603 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6604 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6605 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6606 ioc->facts.CurReplyFrameSize,
6607 ioc->facts.ReplyQueueDepth);
6608
6609 len += sprintf(buf+len, " MaxDevices = %d\n",
6610 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6611 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6612
6613 /* per-port info */
6614 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6615 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6616 p+1,
6617 ioc->facts.NumberOfPorts);
6618 if (ioc->bus_type == FC) {
6619 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6620 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6621 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6622 a[5], a[4], a[3], a[2], a[1], a[0]);
6623 }
6624 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6625 ioc->fc_port_page0[p].WWNN.High,
6626 ioc->fc_port_page0[p].WWNN.Low,
6627 ioc->fc_port_page0[p].WWPN.High,
6628 ioc->fc_port_page0[p].WWPN.Low);
6629 }
6630 }
6631
6632 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6633}
6634
6635#endif /* CONFIG_PROC_FS } */
6636
6637/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6638static void
6639mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6640{
6641 buf[0] ='\0';
6642 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6643 sprintf(buf, " (Exp %02d%02d)",
6644 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6645 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6646
6647 /* insider hack! */
6648 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6649 strcat(buf, " [MDBG]");
6650 }
6651}
6652
6653/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6654/**
6655 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6656 * @ioc: Pointer to MPT_ADAPTER structure
6657 * @buffer: Pointer to buffer where IOC summary info should be written
6658 * @size: Pointer to number of bytes we wrote (set by this routine)
6659 * @len: Offset at which to start writing in buffer
6660 * @showlan: Display LAN stuff?
6661 *
6662 * This routine writes (english readable) ASCII text, which represents
6663 * a summary of IOC information, to a buffer.
6664 */
6665void
6666mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6667{
6668 char expVer[32];
6669 int y;
6670
6671 mpt_get_fw_exp_ver(expVer, ioc);
6672
6673 /*
6674 * Shorter summary of attached ioc's...
6675 */
6676 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6677 ioc->name,
6678 ioc->prod_name,
6679 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6680 ioc->facts.FWVersion.Word,
6681 expVer,
6682 ioc->facts.NumberOfPorts,
6683 ioc->req_depth);
6684
6685 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6686 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6687 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6688 a[5], a[4], a[3], a[2], a[1], a[0]);
6689 }
6690
Linus Torvalds1da177e2005-04-16 15:20:36 -07006691 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006692
6693 if (!ioc->active)
6694 y += sprintf(buffer+len+y, " (disabled)");
6695
6696 y += sprintf(buffer+len+y, "\n");
6697
6698 *size = y;
6699}
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306700/**
6701 * mpt_set_taskmgmt_in_progress_flag - set flags associated with task managment
6702 * @ioc: Pointer to MPT_ADAPTER structure
6703 *
6704 * Returns 0 for SUCCESS or -1 if FAILED.
6705 *
6706 * If -1 is return, then it was not possible to set the flags
6707 **/
6708int
6709mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6710{
6711 unsigned long flags;
6712 int retval;
6713
6714 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6715 if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
6716 (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
6717 retval = -1;
6718 goto out;
6719 }
6720 retval = 0;
6721 ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306722 ioc->taskmgmt_quiesce_io = 1;
6723 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306724 ioc->alt_ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306725 ioc->alt_ioc->taskmgmt_quiesce_io = 1;
6726 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306727 out:
6728 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6729 return retval;
6730}
6731EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
6732
6733/**
6734 * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task managment
6735 * @ioc: Pointer to MPT_ADAPTER structure
6736 *
6737 **/
6738void
6739mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6740{
6741 unsigned long flags;
6742
6743 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6744 ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306745 ioc->taskmgmt_quiesce_io = 0;
6746 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306747 ioc->alt_ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306748 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
6749 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306750 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6751}
6752EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006753
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306754
6755/**
6756 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6757 * the kernel
6758 * @ioc: Pointer to MPT_ADAPTER structure
6759 *
6760 **/
6761void
6762mpt_halt_firmware(MPT_ADAPTER *ioc)
6763{
6764 u32 ioc_raw_state;
6765
6766 ioc_raw_state = mpt_GetIocState(ioc, 0);
6767
6768 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6769 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6770 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6771 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6772 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6773 } else {
6774 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6775 panic("%s: Firmware is halted due to command timeout\n",
6776 ioc->name);
6777 }
6778}
6779EXPORT_SYMBOL(mpt_halt_firmware);
6780
Linus Torvalds1da177e2005-04-16 15:20:36 -07006781/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6782/*
6783 * Reset Handling
6784 */
6785/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6786/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006787 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006788 * @ioc: Pointer to MPT_ADAPTER structure
6789 * @sleepFlag: Indicates if sleep or schedule must be called.
6790 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006791 * Issues SCSI Task Management call based on input arg values.
6792 * If TaskMgmt fails, returns associated SCSI request.
6793 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006794 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6795 * or a non-interrupt thread. In the former, must not call schedule().
6796 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006797 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006798 * FW reload/initialization failed.
6799 *
6800 * Returns 0 for SUCCESS or -1 if FAILED.
6801 */
6802int
6803mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6804{
6805 int rc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306806 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006807 unsigned long flags;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306808 unsigned long time_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006809
Prakash, Sathya436ace72007-07-24 15:42:08 +05306810 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006811#ifdef MFCNT
6812 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6813 printk("MF count 0x%x !\n", ioc->mfcnt);
6814#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306815 if (mpt_fwfault_debug)
6816 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006817
6818 /* Reset the adapter. Prevent more than 1 call to
6819 * mpt_do_ioc_recovery at any instant in time.
6820 */
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306821 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6822 if (ioc->ioc_reset_in_progress) {
6823 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006824 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006825 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306826 ioc->ioc_reset_in_progress = 1;
6827 if (ioc->alt_ioc)
6828 ioc->alt_ioc->ioc_reset_in_progress = 1;
6829 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006830
6831 /* FIXME: If do_ioc_recovery fails, repeat....
6832 */
6833
6834 /* The SCSI driver needs to adjust timeouts on all current
6835 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006836 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006837 * For all other protocol drivers, this is a no-op.
6838 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05306839 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6840 if (MptResetHandlers[cb_idx]) {
6841 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
6842 if (ioc->alt_ioc)
6843 mpt_signal_reset(cb_idx, ioc->alt_ioc,
6844 MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006845 }
6846 }
6847
Kashyap, Desai2f187862009-05-29 16:52:37 +05306848 time_count = jiffies;
6849 rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
6850 if (rc != 0) {
6851 printk(KERN_WARNING MYNAM
6852 ": WARNING - (%d) Cannot recover %s\n", rc, ioc->name);
6853 } else {
6854 if (ioc->hard_resets < -1)
6855 ioc->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006856 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006857
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306858 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6859 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306860 ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306861 ioc->taskmgmt_in_progress = 0;
6862 if (ioc->alt_ioc) {
6863 ioc->alt_ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306864 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306865 ioc->alt_ioc->taskmgmt_in_progress = 0;
6866 }
6867 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006868
Kashyap, Desai2f187862009-05-29 16:52:37 +05306869 dtmprintk(ioc,
6870 printk(MYIOC_s_DEBUG_FMT
6871 "HardResetHandler: completed (%d seconds): %s\n", ioc->name,
6872 jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?
6873 "SUCCESS" : "FAILED")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006874
6875 return rc;
6876}
6877
Kashyap, Desai2f187862009-05-29 16:52:37 +05306878#ifdef CONFIG_FUSION_LOGGING
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006879static void
Kashyap, Desai2f187862009-05-29 16:52:37 +05306880mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006881{
Eric Moore509e5e52006-04-26 13:22:37 -06006882 char *ds = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306883 u32 evData0;
6884 int ii;
6885 u8 event;
6886 char *evStr = ioc->evStr;
6887
6888 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6889 evData0 = le32_to_cpu(pEventReply->Data[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006890
6891 switch(event) {
6892 case MPI_EVENT_NONE:
6893 ds = "None";
6894 break;
6895 case MPI_EVENT_LOG_DATA:
6896 ds = "Log Data";
6897 break;
6898 case MPI_EVENT_STATE_CHANGE:
6899 ds = "State Change";
6900 break;
6901 case MPI_EVENT_UNIT_ATTENTION:
6902 ds = "Unit Attention";
6903 break;
6904 case MPI_EVENT_IOC_BUS_RESET:
6905 ds = "IOC Bus Reset";
6906 break;
6907 case MPI_EVENT_EXT_BUS_RESET:
6908 ds = "External Bus Reset";
6909 break;
6910 case MPI_EVENT_RESCAN:
6911 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006912 break;
6913 case MPI_EVENT_LINK_STATUS_CHANGE:
6914 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6915 ds = "Link Status(FAILURE) Change";
6916 else
6917 ds = "Link Status(ACTIVE) Change";
6918 break;
6919 case MPI_EVENT_LOOP_STATE_CHANGE:
6920 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6921 ds = "Loop State(LIP) Change";
6922 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Kashyap, Desai2f187862009-05-29 16:52:37 +05306923 ds = "Loop State(LPE) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006924 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05306925 ds = "Loop State(LPB) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006926 break;
6927 case MPI_EVENT_LOGOUT:
6928 ds = "Logout";
6929 break;
6930 case MPI_EVENT_EVENT_CHANGE:
6931 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006932 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006933 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006934 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006935 break;
6936 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006937 {
6938 u8 ReasonCode = (u8)(evData0 >> 16);
6939 switch (ReasonCode) {
6940 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6941 ds = "Integrated Raid: Volume Created";
6942 break;
6943 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6944 ds = "Integrated Raid: Volume Deleted";
6945 break;
6946 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6947 ds = "Integrated Raid: Volume Settings Changed";
6948 break;
6949 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6950 ds = "Integrated Raid: Volume Status Changed";
6951 break;
6952 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6953 ds = "Integrated Raid: Volume Physdisk Changed";
6954 break;
6955 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6956 ds = "Integrated Raid: Physdisk Created";
6957 break;
6958 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6959 ds = "Integrated Raid: Physdisk Deleted";
6960 break;
6961 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6962 ds = "Integrated Raid: Physdisk Settings Changed";
6963 break;
6964 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6965 ds = "Integrated Raid: Physdisk Status Changed";
6966 break;
6967 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6968 ds = "Integrated Raid: Domain Validation Needed";
6969 break;
6970 case MPI_EVENT_RAID_RC_SMART_DATA :
6971 ds = "Integrated Raid; Smart Data";
6972 break;
6973 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6974 ds = "Integrated Raid: Replace Action Started";
6975 break;
6976 default:
6977 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006978 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006979 }
6980 break;
6981 }
6982 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6983 ds = "SCSI Device Status Change";
6984 break;
6985 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6986 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006987 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006988 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006989 u8 ReasonCode = (u8)(evData0 >> 16);
6990 switch (ReasonCode) {
6991 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006992 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006993 "SAS Device Status Change: Added: "
6994 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006995 break;
6996 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006997 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006998 "SAS Device Status Change: Deleted: "
6999 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007000 break;
7001 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06007002 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007003 "SAS Device Status Change: SMART Data: "
7004 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007005 break;
7006 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007007 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007008 "SAS Device Status Change: No Persistancy: "
7009 "id=%d channel=%d", id, channel);
7010 break;
7011 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
7012 snprintf(evStr, EVENT_DESCR_STR_SZ,
7013 "SAS Device Status Change: Unsupported Device "
7014 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007015 break;
7016 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
7017 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007018 "SAS Device Status Change: Internal Device "
7019 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007020 break;
7021 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
7022 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007023 "SAS Device Status Change: Internal Task "
7024 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007025 break;
7026 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
7027 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007028 "SAS Device Status Change: Internal Abort "
7029 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007030 break;
7031 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
7032 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007033 "SAS Device Status Change: Internal Clear "
7034 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007035 break;
7036 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
7037 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007038 "SAS Device Status Change: Internal Query "
7039 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007040 break;
7041 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007042 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007043 "SAS Device Status Change: Unknown: "
7044 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06007045 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007046 }
7047 break;
7048 }
7049 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
7050 ds = "Bus Timer Expired";
7051 break;
7052 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07007053 {
7054 u16 curr_depth = (u16)(evData0 >> 16);
7055 u8 channel = (u8)(evData0 >> 8);
7056 u8 id = (u8)(evData0);
7057
7058 snprintf(evStr, EVENT_DESCR_STR_SZ,
7059 "Queue Full: channel=%d id=%d depth=%d",
7060 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007061 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07007062 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007063 case MPI_EVENT_SAS_SES:
7064 ds = "SAS SES Event";
7065 break;
7066 case MPI_EVENT_PERSISTENT_TABLE_FULL:
7067 ds = "Persistent Table Full";
7068 break;
7069 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07007070 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007071 u8 LinkRates = (u8)(evData0 >> 8);
7072 u8 PhyNumber = (u8)(evData0);
7073 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
7074 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
7075 switch (LinkRates) {
7076 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06007077 snprintf(evStr, EVENT_DESCR_STR_SZ,
7078 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007079 " Rate Unknown",PhyNumber);
7080 break;
7081 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06007082 snprintf(evStr, EVENT_DESCR_STR_SZ,
7083 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007084 " Phy Disabled",PhyNumber);
7085 break;
7086 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06007087 snprintf(evStr, EVENT_DESCR_STR_SZ,
7088 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007089 " Failed Speed Nego",PhyNumber);
7090 break;
7091 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06007092 snprintf(evStr, EVENT_DESCR_STR_SZ,
7093 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007094 " Sata OOB Completed",PhyNumber);
7095 break;
7096 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06007097 snprintf(evStr, EVENT_DESCR_STR_SZ,
7098 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007099 " Rate 1.5 Gbps",PhyNumber);
7100 break;
7101 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06007102 snprintf(evStr, EVENT_DESCR_STR_SZ,
7103 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007104 " Rate 3.0 Gpbs",PhyNumber);
7105 break;
7106 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007107 snprintf(evStr, EVENT_DESCR_STR_SZ,
7108 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007109 break;
7110 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007111 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007112 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007113 case MPI_EVENT_SAS_DISCOVERY_ERROR:
7114 ds = "SAS Discovery Error";
7115 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007116 case MPI_EVENT_IR_RESYNC_UPDATE:
7117 {
7118 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06007119 snprintf(evStr, EVENT_DESCR_STR_SZ,
7120 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07007121 break;
7122 }
7123 case MPI_EVENT_IR2:
7124 {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307125 u8 id = (u8)(evData0);
7126 u8 channel = (u8)(evData0 >> 8);
7127 u8 phys_num = (u8)(evData0 >> 24);
Moore, Eric3a892be2006-03-14 09:14:03 -07007128 u8 ReasonCode = (u8)(evData0 >> 16);
Kashyap, Desai2f187862009-05-29 16:52:37 +05307129
Moore, Eric3a892be2006-03-14 09:14:03 -07007130 switch (ReasonCode) {
7131 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307132 snprintf(evStr, EVENT_DESCR_STR_SZ,
7133 "IR2: LD State Changed: "
7134 "id=%d channel=%d phys_num=%d",
7135 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007136 break;
7137 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307138 snprintf(evStr, EVENT_DESCR_STR_SZ,
7139 "IR2: PD State Changed "
7140 "id=%d channel=%d phys_num=%d",
7141 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007142 break;
7143 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307144 snprintf(evStr, EVENT_DESCR_STR_SZ,
7145 "IR2: Bad Block Table Full: "
7146 "id=%d channel=%d phys_num=%d",
7147 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007148 break;
7149 case MPI_EVENT_IR2_RC_PD_INSERTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307150 snprintf(evStr, EVENT_DESCR_STR_SZ,
7151 "IR2: PD Inserted: "
7152 "id=%d channel=%d phys_num=%d",
7153 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007154 break;
7155 case MPI_EVENT_IR2_RC_PD_REMOVED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307156 snprintf(evStr, EVENT_DESCR_STR_SZ,
7157 "IR2: PD Removed: "
7158 "id=%d channel=%d phys_num=%d",
7159 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007160 break;
7161 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307162 snprintf(evStr, EVENT_DESCR_STR_SZ,
7163 "IR2: Foreign CFG Detected: "
7164 "id=%d channel=%d phys_num=%d",
7165 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007166 break;
7167 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307168 snprintf(evStr, EVENT_DESCR_STR_SZ,
7169 "IR2: Rebuild Medium Error: "
7170 "id=%d channel=%d phys_num=%d",
7171 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007172 break;
7173 default:
7174 ds = "IR2";
7175 break;
7176 }
7177 break;
7178 }
7179 case MPI_EVENT_SAS_DISCOVERY:
7180 {
7181 if (evData0)
7182 ds = "SAS Discovery: Start";
7183 else
7184 ds = "SAS Discovery: Stop";
7185 break;
7186 }
7187 case MPI_EVENT_LOG_ENTRY_ADDED:
7188 ds = "SAS Log Entry Added";
7189 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007190
Eric Moorec6c727a2007-01-29 09:44:54 -07007191 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
7192 {
7193 u8 phy_num = (u8)(evData0);
7194 u8 port_num = (u8)(evData0 >> 8);
7195 u8 port_width = (u8)(evData0 >> 16);
7196 u8 primative = (u8)(evData0 >> 24);
7197 snprintf(evStr, EVENT_DESCR_STR_SZ,
7198 "SAS Broadcase Primative: phy=%d port=%d "
7199 "width=%d primative=0x%02x",
7200 phy_num, port_num, port_width, primative);
7201 break;
7202 }
7203
7204 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7205 {
7206 u8 reason = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007207
Kashyap, Desai2f187862009-05-29 16:52:37 +05307208 switch (reason) {
7209 case MPI_EVENT_SAS_INIT_RC_ADDED:
7210 ds = "SAS Initiator Status Change: Added";
7211 break;
7212 case MPI_EVENT_SAS_INIT_RC_REMOVED:
7213 ds = "SAS Initiator Status Change: Deleted";
7214 break;
7215 default:
7216 ds = "SAS Initiator Status Change";
7217 break;
7218 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007219 break;
7220 }
7221
7222 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7223 {
7224 u8 max_init = (u8)(evData0);
7225 u8 current_init = (u8)(evData0 >> 8);
7226
7227 snprintf(evStr, EVENT_DESCR_STR_SZ,
7228 "SAS Initiator Device Table Overflow: max initiators=%02d "
7229 "current initators=%02d",
7230 max_init, current_init);
7231 break;
7232 }
7233 case MPI_EVENT_SAS_SMP_ERROR:
7234 {
7235 u8 status = (u8)(evData0);
7236 u8 port_num = (u8)(evData0 >> 8);
7237 u8 result = (u8)(evData0 >> 16);
7238
7239 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7240 snprintf(evStr, EVENT_DESCR_STR_SZ,
7241 "SAS SMP Error: port=%d result=0x%02x",
7242 port_num, result);
7243 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7244 snprintf(evStr, EVENT_DESCR_STR_SZ,
7245 "SAS SMP Error: port=%d : CRC Error",
7246 port_num);
7247 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7248 snprintf(evStr, EVENT_DESCR_STR_SZ,
7249 "SAS SMP Error: port=%d : Timeout",
7250 port_num);
7251 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7252 snprintf(evStr, EVENT_DESCR_STR_SZ,
7253 "SAS SMP Error: port=%d : No Destination",
7254 port_num);
7255 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7256 snprintf(evStr, EVENT_DESCR_STR_SZ,
7257 "SAS SMP Error: port=%d : Bad Destination",
7258 port_num);
7259 else
7260 snprintf(evStr, EVENT_DESCR_STR_SZ,
7261 "SAS SMP Error: port=%d : status=0x%02x",
7262 port_num, status);
7263 break;
7264 }
7265
Kashyap, Desai2f187862009-05-29 16:52:37 +05307266 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
7267 {
7268 u8 reason = (u8)(evData0);
7269
7270 switch (reason) {
7271 case MPI_EVENT_SAS_EXP_RC_ADDED:
7272 ds = "Expander Status Change: Added";
7273 break;
7274 case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
7275 ds = "Expander Status Change: Deleted";
7276 break;
7277 default:
7278 ds = "Expander Status Change";
7279 break;
7280 }
7281 break;
7282 }
7283
Linus Torvalds1da177e2005-04-16 15:20:36 -07007284 /*
7285 * MPT base "custom" events may be added here...
7286 */
7287 default:
7288 ds = "Unknown";
7289 break;
7290 }
Eric Moore509e5e52006-04-26 13:22:37 -06007291 if (ds)
7292 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007293
Kashyap, Desai2f187862009-05-29 16:52:37 +05307294
7295 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7296 "MPT event:(%02Xh) : %s\n",
7297 ioc->name, event, evStr));
7298
7299 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
7300 ": Event data:\n"));
7301 for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
7302 devtverboseprintk(ioc, printk(" %08x",
7303 le32_to_cpu(pEventReply->Data[ii])));
7304 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
7305}
7306#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007307/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007308/**
7309 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007310 * @ioc: Pointer to MPT_ADAPTER structure
7311 * @pEventReply: Pointer to EventNotification reply frame
7312 * @evHandlers: Pointer to integer, number of event handlers
7313 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007314 * Routes a received EventNotificationReply to all currently registered
7315 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007316 * Returns sum of event handlers return values.
7317 */
7318static int
7319ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7320{
7321 u16 evDataLen;
7322 u32 evData0 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007323 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307324 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007325 int r = 0;
7326 int handlers = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007327 u8 event;
7328
7329 /*
7330 * Do platform normalization of values
7331 */
7332 event = le32_to_cpu(pEventReply->Event) & 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007333 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7334 if (evDataLen) {
7335 evData0 = le32_to_cpu(pEventReply->Data[0]);
7336 }
7337
Prakash, Sathya436ace72007-07-24 15:42:08 +05307338#ifdef CONFIG_FUSION_LOGGING
Kashyap, Desai2f187862009-05-29 16:52:37 +05307339 if (evDataLen)
7340 mpt_display_event_info(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007341#endif
7342
7343 /*
7344 * Do general / base driver event processing
7345 */
7346 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007347 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7348 if (evDataLen) {
7349 u8 evState = evData0 & 0xFF;
7350
7351 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7352
7353 /* Update EventState field in cached IocFacts */
7354 if (ioc->facts.Function) {
7355 ioc->facts.EventState = evState;
7356 }
7357 }
7358 break;
Moore, Ericece50912006-01-16 18:53:19 -07007359 case MPI_EVENT_INTEGRATED_RAID:
7360 mptbase_raid_process_event_data(ioc,
7361 (MpiEventDataRaid_t *)pEventReply->Data);
7362 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007363 default:
7364 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007365 }
7366
7367 /*
7368 * Should this event be logged? Events are written sequentially.
7369 * When buffer is full, start again at the top.
7370 */
7371 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7372 int idx;
7373
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007374 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007375
7376 ioc->events[idx].event = event;
7377 ioc->events[idx].eventContext = ioc->eventContext;
7378
7379 for (ii = 0; ii < 2; ii++) {
7380 if (ii < evDataLen)
7381 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7382 else
7383 ioc->events[idx].data[ii] = 0;
7384 }
7385
7386 ioc->eventContext++;
7387 }
7388
7389
7390 /*
7391 * Call each currently registered protocol event handler.
7392 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007393 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307394 if (MptEvHandlers[cb_idx]) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307395 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7396 "Routing Event to event handler #%d\n",
7397 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307398 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007399 handlers++;
7400 }
7401 }
7402 /* FIXME? Examine results here? */
7403
7404 /*
7405 * If needed, send (a single) EventAck.
7406 */
7407 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307408 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007409 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007410 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307411 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007412 ioc->name, ii));
7413 }
7414 }
7415
7416 *evHandlers = handlers;
7417 return r;
7418}
7419
7420/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007421/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007422 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7423 * @ioc: Pointer to MPT_ADAPTER structure
7424 * @log_info: U32 LogInfo reply word from the IOC
7425 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007426 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007427 */
7428static void
7429mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7430{
Eric Moore7c431e52007-06-13 16:34:36 -06007431 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007432
Eric Moore7c431e52007-06-13 16:34:36 -06007433 switch (log_info & 0xFF000000) {
7434 case MPI_IOCLOGINFO_FC_INIT_BASE:
7435 desc = "FCP Initiator";
7436 break;
7437 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7438 desc = "FCP Target";
7439 break;
7440 case MPI_IOCLOGINFO_FC_LAN_BASE:
7441 desc = "LAN";
7442 break;
7443 case MPI_IOCLOGINFO_FC_MSG_BASE:
7444 desc = "MPI Message Layer";
7445 break;
7446 case MPI_IOCLOGINFO_FC_LINK_BASE:
7447 desc = "FC Link";
7448 break;
7449 case MPI_IOCLOGINFO_FC_CTX_BASE:
7450 desc = "Context Manager";
7451 break;
7452 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7453 desc = "Invalid Field Offset";
7454 break;
7455 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7456 desc = "State Change Info";
7457 break;
7458 }
7459
7460 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7461 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007462}
7463
7464/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007465/**
Moore, Eric335a9412006-01-17 17:06:23 -07007466 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007467 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007468 * @log_info: U32 LogInfo word from the IOC
7469 *
7470 * Refer to lsi/sp_log.h.
7471 */
7472static void
Moore, Eric335a9412006-01-17 17:06:23 -07007473mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007474{
7475 u32 info = log_info & 0x00FF0000;
7476 char *desc = "unknown";
7477
7478 switch (info) {
7479 case 0x00010000:
7480 desc = "bug! MID not found";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007481 break;
7482
7483 case 0x00020000:
7484 desc = "Parity Error";
7485 break;
7486
7487 case 0x00030000:
7488 desc = "ASYNC Outbound Overrun";
7489 break;
7490
7491 case 0x00040000:
7492 desc = "SYNC Offset Error";
7493 break;
7494
7495 case 0x00050000:
7496 desc = "BM Change";
7497 break;
7498
7499 case 0x00060000:
7500 desc = "Msg In Overflow";
7501 break;
7502
7503 case 0x00070000:
7504 desc = "DMA Error";
7505 break;
7506
7507 case 0x00080000:
7508 desc = "Outbound DMA Overrun";
7509 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007510
Linus Torvalds1da177e2005-04-16 15:20:36 -07007511 case 0x00090000:
7512 desc = "Task Management";
7513 break;
7514
7515 case 0x000A0000:
7516 desc = "Device Problem";
7517 break;
7518
7519 case 0x000B0000:
7520 desc = "Invalid Phase Change";
7521 break;
7522
7523 case 0x000C0000:
7524 desc = "Untagged Table Size";
7525 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007526
Linus Torvalds1da177e2005-04-16 15:20:36 -07007527 }
7528
7529 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7530}
7531
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007532/* strings for sas loginfo */
7533 static char *originator_str[] = {
7534 "IOP", /* 00h */
7535 "PL", /* 01h */
7536 "IR" /* 02h */
7537 };
7538 static char *iop_code_str[] = {
7539 NULL, /* 00h */
7540 "Invalid SAS Address", /* 01h */
7541 NULL, /* 02h */
7542 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007543 "Diag Message Error", /* 04h */
7544 "Task Terminated", /* 05h */
7545 "Enclosure Management", /* 06h */
7546 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007547 };
7548 static char *pl_code_str[] = {
7549 NULL, /* 00h */
7550 "Open Failure", /* 01h */
7551 "Invalid Scatter Gather List", /* 02h */
7552 "Wrong Relative Offset or Frame Length", /* 03h */
7553 "Frame Transfer Error", /* 04h */
7554 "Transmit Frame Connected Low", /* 05h */
7555 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7556 "SATA Read Log Receive Data Error", /* 07h */
7557 "SATA NCQ Fail All Commands After Error", /* 08h */
7558 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7559 "Receive Frame Invalid Message", /* 0Ah */
7560 "Receive Context Message Valid Error", /* 0Bh */
7561 "Receive Frame Current Frame Error", /* 0Ch */
7562 "SATA Link Down", /* 0Dh */
7563 "Discovery SATA Init W IOS", /* 0Eh */
7564 "Config Invalid Page", /* 0Fh */
7565 "Discovery SATA Init Timeout", /* 10h */
7566 "Reset", /* 11h */
7567 "Abort", /* 12h */
7568 "IO Not Yet Executed", /* 13h */
7569 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007570 "Persistent Reservation Out Not Affiliation "
7571 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007572 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007573 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007574 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007575 NULL, /* 19h */
7576 NULL, /* 1Ah */
7577 NULL, /* 1Bh */
7578 NULL, /* 1Ch */
7579 NULL, /* 1Dh */
7580 NULL, /* 1Eh */
7581 NULL, /* 1Fh */
7582 "Enclosure Management" /* 20h */
7583 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007584 static char *ir_code_str[] = {
7585 "Raid Action Error", /* 00h */
7586 NULL, /* 00h */
7587 NULL, /* 01h */
7588 NULL, /* 02h */
7589 NULL, /* 03h */
7590 NULL, /* 04h */
7591 NULL, /* 05h */
7592 NULL, /* 06h */
7593 NULL /* 07h */
7594 };
7595 static char *raid_sub_code_str[] = {
7596 NULL, /* 00h */
7597 "Volume Creation Failed: Data Passed too "
7598 "Large", /* 01h */
7599 "Volume Creation Failed: Duplicate Volumes "
7600 "Attempted", /* 02h */
7601 "Volume Creation Failed: Max Number "
7602 "Supported Volumes Exceeded", /* 03h */
7603 "Volume Creation Failed: DMA Error", /* 04h */
7604 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7605 "Volume Creation Failed: Error Reading "
7606 "MFG Page 4", /* 06h */
7607 "Volume Creation Failed: Creating Internal "
7608 "Structures", /* 07h */
7609 NULL, /* 08h */
7610 NULL, /* 09h */
7611 NULL, /* 0Ah */
7612 NULL, /* 0Bh */
7613 NULL, /* 0Ch */
7614 NULL, /* 0Dh */
7615 NULL, /* 0Eh */
7616 NULL, /* 0Fh */
7617 "Activation failed: Already Active Volume", /* 10h */
7618 "Activation failed: Unsupported Volume Type", /* 11h */
7619 "Activation failed: Too Many Active Volumes", /* 12h */
7620 "Activation failed: Volume ID in Use", /* 13h */
7621 "Activation failed: Reported Failure", /* 14h */
7622 "Activation failed: Importing a Volume", /* 15h */
7623 NULL, /* 16h */
7624 NULL, /* 17h */
7625 NULL, /* 18h */
7626 NULL, /* 19h */
7627 NULL, /* 1Ah */
7628 NULL, /* 1Bh */
7629 NULL, /* 1Ch */
7630 NULL, /* 1Dh */
7631 NULL, /* 1Eh */
7632 NULL, /* 1Fh */
7633 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7634 "Phys Disk failed: Data Passed too Large", /* 21h */
7635 "Phys Disk failed: DMA Error", /* 22h */
7636 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7637 "Phys Disk failed: Creating Phys Disk Config "
7638 "Page", /* 24h */
7639 NULL, /* 25h */
7640 NULL, /* 26h */
7641 NULL, /* 27h */
7642 NULL, /* 28h */
7643 NULL, /* 29h */
7644 NULL, /* 2Ah */
7645 NULL, /* 2Bh */
7646 NULL, /* 2Ch */
7647 NULL, /* 2Dh */
7648 NULL, /* 2Eh */
7649 NULL, /* 2Fh */
7650 "Compatibility Error: IR Disabled", /* 30h */
7651 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7652 "Compatibility Error: Device not Direct Access "
7653 "Device ", /* 32h */
7654 "Compatibility Error: Removable Device Found", /* 33h */
7655 "Compatibility Error: Device SCSI Version not "
7656 "2 or Higher", /* 34h */
7657 "Compatibility Error: SATA Device, 48 BIT LBA "
7658 "not Supported", /* 35h */
7659 "Compatibility Error: Device doesn't have "
7660 "512 Byte Block Sizes", /* 36h */
7661 "Compatibility Error: Volume Type Check Failed", /* 37h */
7662 "Compatibility Error: Volume Type is "
7663 "Unsupported by FW", /* 38h */
7664 "Compatibility Error: Disk Drive too Small for "
7665 "use in Volume", /* 39h */
7666 "Compatibility Error: Phys Disk for Create "
7667 "Volume not Found", /* 3Ah */
7668 "Compatibility Error: Too Many or too Few "
7669 "Disks for Volume Type", /* 3Bh */
7670 "Compatibility Error: Disk stripe Sizes "
7671 "Must be 64KB", /* 3Ch */
7672 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7673 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007674
7675/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007676/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007677 * mpt_sas_log_info - Log information returned from SAS IOC.
7678 * @ioc: Pointer to MPT_ADAPTER structure
7679 * @log_info: U32 LogInfo reply word from the IOC
7680 *
7681 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007682 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007683static void
7684mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7685{
7686union loginfo_type {
7687 u32 loginfo;
7688 struct {
7689 u32 subcode:16;
7690 u32 code:8;
7691 u32 originator:4;
7692 u32 bus_type:4;
7693 }dw;
7694};
7695 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007696 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007697 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007698 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007699
7700 sas_loginfo.loginfo = log_info;
7701 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007702 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007703 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007704
7705 originator_desc = originator_str[sas_loginfo.dw.originator];
7706
7707 switch (sas_loginfo.dw.originator) {
7708
7709 case 0: /* IOP */
7710 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007711 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007712 code_desc = iop_code_str[sas_loginfo.dw.code];
7713 break;
7714 case 1: /* PL */
7715 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007716 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007717 code_desc = pl_code_str[sas_loginfo.dw.code];
7718 break;
7719 case 2: /* IR */
7720 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007721 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007722 break;
7723 code_desc = ir_code_str[sas_loginfo.dw.code];
7724 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007725 ARRAY_SIZE(raid_sub_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007726 break;
7727 if (sas_loginfo.dw.code == 0)
7728 sub_code_desc =
7729 raid_sub_code_str[sas_loginfo.dw.subcode];
7730 break;
7731 default:
7732 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007733 }
7734
Eric Moorec6c727a2007-01-29 09:44:54 -07007735 if (sub_code_desc != NULL)
7736 printk(MYIOC_s_INFO_FMT
7737 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7738 " SubCode={%s}\n",
7739 ioc->name, log_info, originator_desc, code_desc,
7740 sub_code_desc);
7741 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007742 printk(MYIOC_s_INFO_FMT
7743 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7744 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007745 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007746 sas_loginfo.dw.subcode);
7747 else
7748 printk(MYIOC_s_INFO_FMT
7749 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7750 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007751 ioc->name, log_info, originator_desc,
7752 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007753}
7754
Linus Torvalds1da177e2005-04-16 15:20:36 -07007755/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007756/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007757 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7758 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007759 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007760 * @mf: Pointer to MPT request frame
7761 *
7762 * Refer to lsi/mpi.h.
7763 **/
7764static void
7765mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7766{
7767 Config_t *pReq = (Config_t *)mf;
7768 char extend_desc[EVENT_DESCR_STR_SZ];
7769 char *desc = NULL;
7770 u32 form;
7771 u8 page_type;
7772
7773 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7774 page_type = pReq->ExtPageType;
7775 else
7776 page_type = pReq->Header.PageType;
7777
7778 /*
7779 * ignore invalid page messages for GET_NEXT_HANDLE
7780 */
7781 form = le32_to_cpu(pReq->PageAddress);
7782 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7783 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7784 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7785 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7786 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7787 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7788 return;
7789 }
7790 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7791 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7792 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7793 return;
7794 }
7795
7796 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7797 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7798 page_type, pReq->Header.PageNumber, pReq->Action, form);
7799
7800 switch (ioc_status) {
7801
7802 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7803 desc = "Config Page Invalid Action";
7804 break;
7805
7806 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7807 desc = "Config Page Invalid Type";
7808 break;
7809
7810 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7811 desc = "Config Page Invalid Page";
7812 break;
7813
7814 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7815 desc = "Config Page Invalid Data";
7816 break;
7817
7818 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7819 desc = "Config Page No Defaults";
7820 break;
7821
7822 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7823 desc = "Config Page Can't Commit";
7824 break;
7825 }
7826
7827 if (!desc)
7828 return;
7829
Eric Moore29dd3602007-09-14 18:46:51 -06007830 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7831 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007832}
7833
7834/**
7835 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007836 * @ioc: Pointer to MPT_ADAPTER structure
7837 * @ioc_status: U32 IOCStatus word from IOC
7838 * @mf: Pointer to MPT request frame
7839 *
7840 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007841 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007842static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007843mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007844{
7845 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007846 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007847
7848 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007849
7850/****************************************************************************/
7851/* Common IOCStatus values for all replies */
7852/****************************************************************************/
7853
Linus Torvalds1da177e2005-04-16 15:20:36 -07007854 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7855 desc = "Invalid Function";
7856 break;
7857
7858 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7859 desc = "Busy";
7860 break;
7861
7862 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7863 desc = "Invalid SGL";
7864 break;
7865
7866 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7867 desc = "Internal Error";
7868 break;
7869
7870 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7871 desc = "Reserved";
7872 break;
7873
7874 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7875 desc = "Insufficient Resources";
7876 break;
7877
7878 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7879 desc = "Invalid Field";
7880 break;
7881
7882 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7883 desc = "Invalid State";
7884 break;
7885
Eric Moorec6c727a2007-01-29 09:44:54 -07007886/****************************************************************************/
7887/* Config IOCStatus values */
7888/****************************************************************************/
7889
Linus Torvalds1da177e2005-04-16 15:20:36 -07007890 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7891 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7892 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7893 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7894 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7895 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007896 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007897 break;
7898
Eric Moorec6c727a2007-01-29 09:44:54 -07007899/****************************************************************************/
7900/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7901/* */
7902/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7903/* */
7904/****************************************************************************/
7905
Linus Torvalds1da177e2005-04-16 15:20:36 -07007906 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007907 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007908 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7909 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7910 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7911 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007912 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007913 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007914 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007915 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007916 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007917 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007918 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007919 break;
7920
Eric Moorec6c727a2007-01-29 09:44:54 -07007921/****************************************************************************/
7922/* SCSI Target values */
7923/****************************************************************************/
7924
7925 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7926 desc = "Target: Priority IO";
7927 break;
7928
7929 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7930 desc = "Target: Invalid Port";
7931 break;
7932
7933 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7934 desc = "Target Invalid IO Index:";
7935 break;
7936
7937 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7938 desc = "Target: Aborted";
7939 break;
7940
7941 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7942 desc = "Target: No Conn Retryable";
7943 break;
7944
7945 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7946 desc = "Target: No Connection";
7947 break;
7948
7949 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7950 desc = "Target: Transfer Count Mismatch";
7951 break;
7952
7953 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7954 desc = "Target: STS Data not Sent";
7955 break;
7956
7957 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7958 desc = "Target: Data Offset Error";
7959 break;
7960
7961 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7962 desc = "Target: Too Much Write Data";
7963 break;
7964
7965 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7966 desc = "Target: IU Too Short";
7967 break;
7968
7969 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7970 desc = "Target: ACK NAK Timeout";
7971 break;
7972
7973 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7974 desc = "Target: Nak Received";
7975 break;
7976
7977/****************************************************************************/
7978/* Fibre Channel Direct Access values */
7979/****************************************************************************/
7980
7981 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7982 desc = "FC: Aborted";
7983 break;
7984
7985 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7986 desc = "FC: RX ID Invalid";
7987 break;
7988
7989 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7990 desc = "FC: DID Invalid";
7991 break;
7992
7993 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7994 desc = "FC: Node Logged Out";
7995 break;
7996
7997 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7998 desc = "FC: Exchange Canceled";
7999 break;
8000
8001/****************************************************************************/
8002/* LAN values */
8003/****************************************************************************/
8004
8005 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
8006 desc = "LAN: Device not Found";
8007 break;
8008
8009 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
8010 desc = "LAN: Device Failure";
8011 break;
8012
8013 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
8014 desc = "LAN: Transmit Error";
8015 break;
8016
8017 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
8018 desc = "LAN: Transmit Aborted";
8019 break;
8020
8021 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
8022 desc = "LAN: Receive Error";
8023 break;
8024
8025 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
8026 desc = "LAN: Receive Aborted";
8027 break;
8028
8029 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
8030 desc = "LAN: Partial Packet";
8031 break;
8032
8033 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
8034 desc = "LAN: Canceled";
8035 break;
8036
8037/****************************************************************************/
8038/* Serial Attached SCSI values */
8039/****************************************************************************/
8040
8041 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
8042 desc = "SAS: SMP Request Failed";
8043 break;
8044
8045 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
8046 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07008047 break;
8048
8049 default:
8050 desc = "Others";
8051 break;
8052 }
Eric Moorec6c727a2007-01-29 09:44:54 -07008053
8054 if (!desc)
8055 return;
8056
Eric Moore29dd3602007-09-14 18:46:51 -06008057 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
8058 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008059}
8060
8061/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008062EXPORT_SYMBOL(mpt_attach);
8063EXPORT_SYMBOL(mpt_detach);
8064#ifdef CONFIG_PM
8065EXPORT_SYMBOL(mpt_resume);
8066EXPORT_SYMBOL(mpt_suspend);
8067#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07008068EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008069EXPORT_SYMBOL(mpt_register);
8070EXPORT_SYMBOL(mpt_deregister);
8071EXPORT_SYMBOL(mpt_event_register);
8072EXPORT_SYMBOL(mpt_event_deregister);
8073EXPORT_SYMBOL(mpt_reset_register);
8074EXPORT_SYMBOL(mpt_reset_deregister);
8075EXPORT_SYMBOL(mpt_device_driver_register);
8076EXPORT_SYMBOL(mpt_device_driver_deregister);
8077EXPORT_SYMBOL(mpt_get_msg_frame);
8078EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05308079EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008080EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008081EXPORT_SYMBOL(mpt_send_handshake_request);
8082EXPORT_SYMBOL(mpt_verify_adapter);
8083EXPORT_SYMBOL(mpt_GetIocState);
8084EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008085EXPORT_SYMBOL(mpt_HardResetHandler);
8086EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008087EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008088EXPORT_SYMBOL(mpt_alloc_fw_memory);
8089EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02008090EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07008091EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008092
Linus Torvalds1da177e2005-04-16 15:20:36 -07008093/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008094/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008095 * fusion_init - Fusion MPT base driver initialization routine.
8096 *
8097 * Returns 0 for success, non-zero for failure.
8098 */
8099static int __init
8100fusion_init(void)
8101{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308102 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008103
8104 show_mptmod_ver(my_NAME, my_VERSION);
8105 printk(KERN_INFO COPYRIGHT "\n");
8106
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308107 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
8108 MptCallbacks[cb_idx] = NULL;
8109 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
8110 MptEvHandlers[cb_idx] = NULL;
8111 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008112 }
8113
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008114 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07008115 * EventNotification handling.
8116 */
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05308117 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008118
8119 /* Register for hard reset handling callbacks.
8120 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05308121 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008122
8123#ifdef CONFIG_PROC_FS
8124 (void) procmpt_create();
8125#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008126 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008127}
8128
8129/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008130/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008131 * fusion_exit - Perform driver unload cleanup.
8132 *
8133 * This routine frees all resources associated with each MPT adapter
8134 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
8135 */
8136static void __exit
8137fusion_exit(void)
8138{
8139
Linus Torvalds1da177e2005-04-16 15:20:36 -07008140 mpt_reset_deregister(mpt_base_index);
8141
8142#ifdef CONFIG_PROC_FS
8143 procmpt_destroy();
8144#endif
8145}
8146
Linus Torvalds1da177e2005-04-16 15:20:36 -07008147module_init(fusion_init);
8148module_exit(fusion_exit);