blob: 8f04d37fb359ba277d2993534825c6046a874279 [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
2670 /* Disable adapter interrupts! */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302671 synchronize_irq(ioc->pcidev->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2673 ioc->active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302674
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 /* Clear any lingering interrupt */
2676 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302677 CHIPREG_READ32(&ioc->chip->IntStatus);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678
2679 if (ioc->alloc != NULL) {
2680 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002681 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2682 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 pci_free_consistent(ioc->pcidev, sz,
2684 ioc->alloc, ioc->alloc_dma);
2685 ioc->reply_frames = NULL;
2686 ioc->req_frames = NULL;
2687 ioc->alloc = NULL;
2688 ioc->alloc_total -= sz;
2689 }
2690
2691 if (ioc->sense_buf_pool != NULL) {
2692 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2693 pci_free_consistent(ioc->pcidev, sz,
2694 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2695 ioc->sense_buf_pool = NULL;
2696 ioc->alloc_total -= sz;
2697 }
2698
2699 if (ioc->events != NULL){
2700 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2701 kfree(ioc->events);
2702 ioc->events = NULL;
2703 ioc->alloc_total -= sz;
2704 }
2705
Prakash, Sathya984621b2008-01-11 14:42:17 +05302706 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002708 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002709 mpt_inactive_raid_list_free(ioc);
2710 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002711 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002712 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002713 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714
2715 if (ioc->spi_data.pIocPg4 != NULL) {
2716 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302717 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 ioc->spi_data.pIocPg4,
2719 ioc->spi_data.IocPg4_dma);
2720 ioc->spi_data.pIocPg4 = NULL;
2721 ioc->alloc_total -= sz;
2722 }
2723
2724 if (ioc->ReqToChain != NULL) {
2725 kfree(ioc->ReqToChain);
2726 kfree(ioc->RequestNB);
2727 ioc->ReqToChain = NULL;
2728 }
2729
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002730 kfree(ioc->ChainToChain);
2731 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002732
2733 if (ioc->HostPageBuffer != NULL) {
2734 if((ret = mpt_host_page_access_control(ioc,
2735 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002736 printk(MYIOC_s_ERR_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302737 ": %s: host page buffers free failed (%d)!\n",
2738 ioc->name, __func__, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002739 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302740 dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2741 "HostPageBuffer free @ %p, sz=%d bytes\n",
2742 ioc->name, ioc->HostPageBuffer,
2743 ioc->HostPageBuffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002744 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002745 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002746 ioc->HostPageBuffer = NULL;
2747 ioc->HostPageBuffer_sz = 0;
2748 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750
Kashyap, Desai2f187862009-05-29 16:52:37 +05302751 pci_set_drvdata(ioc->pcidev, NULL);
2752}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002754/**
2755 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 * @ioc: Pointer to MPT adapter structure
2757 *
2758 * This routine unregisters h/w resources and frees all alloc'd memory
2759 * associated with a MPT adapter structure.
2760 */
2761static void
2762mpt_adapter_dispose(MPT_ADAPTER *ioc)
2763{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002764 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002766 if (ioc == NULL)
2767 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002769 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002771 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002773 if (ioc->pci_irq != -1) {
2774 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302775 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002776 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002777 ioc->pci_irq = -1;
2778 }
2779
2780 if (ioc->memmap != NULL) {
2781 iounmap(ioc->memmap);
2782 ioc->memmap = NULL;
2783 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302785 pci_disable_device(ioc->pcidev);
2786 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2787
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002789 if (ioc->mtrr_reg > 0) {
2790 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002791 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002792 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793#endif
2794
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002795 /* Zap the adapter lookup ptr! */
2796 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002798 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002799 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2800 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002801
2802 if (ioc->alt_ioc)
2803 ioc->alt_ioc->alt_ioc = NULL;
2804
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002805 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806}
2807
2808/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002809/**
2810 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 * @ioc: Pointer to MPT adapter structure
2812 */
2813static void
2814MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2815{
2816 int i = 0;
2817
2818 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302819 if (ioc->prod_name)
2820 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 printk("Capabilities={");
2822
2823 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2824 printk("Initiator");
2825 i++;
2826 }
2827
2828 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2829 printk("%sTarget", i ? "," : "");
2830 i++;
2831 }
2832
2833 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2834 printk("%sLAN", i ? "," : "");
2835 i++;
2836 }
2837
2838#if 0
2839 /*
2840 * This would probably evoke more questions than it's worth
2841 */
2842 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2843 printk("%sLogBusAddr", i ? "," : "");
2844 i++;
2845 }
2846#endif
2847
2848 printk("}\n");
2849}
2850
2851/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002852/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2854 * @ioc: Pointer to MPT_ADAPTER structure
2855 * @force: Force hard KickStart of IOC
2856 * @sleepFlag: Specifies whether the process can sleep
2857 *
2858 * Returns:
2859 * 1 - DIAG reset and READY
2860 * 0 - READY initially OR soft reset and READY
2861 * -1 - Any failure on KickStart
2862 * -2 - Msg Unit Reset Failed
2863 * -3 - IO Unit Reset Failed
2864 * -4 - IOC owned by a PEER
2865 */
2866static int
2867MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2868{
2869 u32 ioc_state;
2870 int statefault = 0;
2871 int cntdn;
2872 int hard_reset_done = 0;
2873 int r;
2874 int ii;
2875 int whoinit;
2876
2877 /* Get current [raw] IOC state */
2878 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002879 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880
2881 /*
2882 * Check to see if IOC got left/stuck in doorbell handshake
2883 * grip of death. If so, hard reset the IOC.
2884 */
2885 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2886 statefault = 1;
2887 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2888 ioc->name);
2889 }
2890
2891 /* Is it already READY? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302892 if (!statefault &&
2893 ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) {
2894 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2895 "IOC is in READY state\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 return 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302897 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898
2899 /*
2900 * Check to see if IOC is in FAULT state.
2901 */
2902 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2903 statefault = 2;
2904 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002905 ioc->name);
2906 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2907 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 }
2909
2910 /*
2911 * Hmmm... Did it get left operational?
2912 */
2913 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302914 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 ioc->name));
2916
2917 /* Check WhoInit.
2918 * If PCI Peer, exit.
2919 * Else, if no fault conditions are present, issue a MessageUnitReset
2920 * Else, fall through to KickStart case
2921 */
2922 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002923 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2924 "whoinit 0x%x statefault %d force %d\n",
2925 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 if (whoinit == MPI_WHOINIT_PCI_PEER)
2927 return -4;
2928 else {
2929 if ((statefault == 0 ) && (force == 0)) {
2930 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2931 return 0;
2932 }
2933 statefault = 3;
2934 }
2935 }
2936
2937 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2938 if (hard_reset_done < 0)
2939 return -1;
2940
2941 /*
2942 * Loop here waiting for IOC to come READY.
2943 */
2944 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002945 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946
2947 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2948 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2949 /*
2950 * BIOS or previous driver load left IOC in OP state.
2951 * Reset messaging FIFOs.
2952 */
2953 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2954 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2955 return -2;
2956 }
2957 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2958 /*
2959 * Something is wrong. Try to get IOC back
2960 * to a known state.
2961 */
2962 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2963 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2964 return -3;
2965 }
2966 }
2967
2968 ii++; cntdn--;
2969 if (!cntdn) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302970 printk(MYIOC_s_ERR_FMT
2971 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
2972 ioc->name, ioc_state, (int)((ii+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 return -ETIME;
2974 }
2975
2976 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002977 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 } else {
2979 mdelay (1); /* 1 msec delay */
2980 }
2981
2982 }
2983
2984 if (statefault < 3) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302985 printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name,
2986 statefault == 1 ? "stuck handshake" : "IOC FAULT");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 }
2988
2989 return hard_reset_done;
2990}
2991
2992/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002993/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 * mpt_GetIocState - Get the current state of a MPT adapter.
2995 * @ioc: Pointer to MPT_ADAPTER structure
2996 * @cooked: Request raw or cooked IOC state
2997 *
2998 * Returns all IOC Doorbell register bits if cooked==0, else just the
2999 * Doorbell bits in MPI_IOC_STATE_MASK.
3000 */
3001u32
3002mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
3003{
3004 u32 s, sc;
3005
3006 /* Get! */
3007 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 sc = s & MPI_IOC_STATE_MASK;
3009
3010 /* Save! */
3011 ioc->last_state = sc;
3012
3013 return cooked ? sc : s;
3014}
3015
3016/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003017/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 * GetIocFacts - Send IOCFacts request to MPT adapter.
3019 * @ioc: Pointer to MPT_ADAPTER structure
3020 * @sleepFlag: Specifies whether the process can sleep
3021 * @reason: If recovery, only update facts.
3022 *
3023 * Returns 0 for success, non-zero for failure.
3024 */
3025static int
3026GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
3027{
3028 IOCFacts_t get_facts;
3029 IOCFactsReply_t *facts;
3030 int r;
3031 int req_sz;
3032 int reply_sz;
3033 int sz;
3034 u32 status, vv;
3035 u8 shiftFactor=1;
3036
3037 /* IOC *must* NOT be in RESET state! */
3038 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303039 printk(KERN_ERR MYNAM
3040 ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
3041 ioc->name, ioc->last_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 return -44;
3043 }
3044
3045 facts = &ioc->facts;
3046
3047 /* Destination (reply area)... */
3048 reply_sz = sizeof(*facts);
3049 memset(facts, 0, reply_sz);
3050
3051 /* Request area (get_facts on the stack right now!) */
3052 req_sz = sizeof(get_facts);
3053 memset(&get_facts, 0, req_sz);
3054
3055 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
3056 /* Assert: All other get_facts fields are zero! */
3057
Prakash, Sathya436ace72007-07-24 15:42:08 +05303058 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003059 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 ioc->name, req_sz, reply_sz));
3061
3062 /* No non-zero fields in the get_facts request are greater than
3063 * 1 byte in size, so we can just fire it off as is.
3064 */
3065 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3066 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3067 if (r != 0)
3068 return r;
3069
3070 /*
3071 * Now byte swap (GRRR) the necessary fields before any further
3072 * inspection of reply contents.
3073 *
3074 * But need to do some sanity checks on MsgLength (byte) field
3075 * to make sure we don't zero IOC's req_sz!
3076 */
3077 /* Did we get a valid reply? */
3078 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3079 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3080 /*
3081 * If not been here, done that, save off first WhoInit value
3082 */
3083 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3084 ioc->FirstWhoInit = facts->WhoInit;
3085 }
3086
3087 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3088 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3089 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3090 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3091 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003092 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 /* CHECKME! IOCStatus, IOCLogInfo */
3094
3095 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3096 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3097
3098 /*
3099 * FC f/w version changed between 1.1 and 1.2
3100 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3101 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3102 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303103 if (facts->MsgVersion < MPI_VERSION_01_02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 /*
3105 * Handle old FC f/w style, convert to new...
3106 */
3107 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3108 facts->FWVersion.Word =
3109 ((oldv<<12) & 0xFF000000) |
3110 ((oldv<<8) & 0x000FFF00);
3111 } else
3112 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3113
3114 facts->ProductID = le16_to_cpu(facts->ProductID);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303115
Eric Mooreb506ade2007-01-29 09:45:37 -07003116 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3117 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3118 ioc->ir_firmware = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303119
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 facts->CurrentHostMfaHighAddr =
3121 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3122 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3123 facts->CurrentSenseBufferHighAddr =
3124 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3125 facts->CurReplyFrameSize =
3126 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003127 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128
3129 /*
3130 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3131 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3132 * to 14 in MPI-1.01.0x.
3133 */
3134 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
Kashyap, Desai2f187862009-05-29 16:52:37 +05303135 facts->MsgVersion > MPI_VERSION_01_00) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3137 }
3138
3139 sz = facts->FWImageSize;
3140 if ( sz & 0x01 )
3141 sz += 1;
3142 if ( sz & 0x02 )
3143 sz += 2;
3144 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003145
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 if (!facts->RequestFrameSize) {
3147 /* Something is wrong! */
3148 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3149 ioc->name);
3150 return -55;
3151 }
3152
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003153 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 vv = ((63 / (sz * 4)) + 1) & 0x03;
3155 ioc->NB_for_64_byte_frame = vv;
3156 while ( sz )
3157 {
3158 shiftFactor++;
3159 sz = sz >> 1;
3160 }
3161 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303162 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003163 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3164 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003165
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3167 /*
3168 * Set values for this IOC's request & reply frame sizes,
3169 * and request & reply queue depths...
3170 */
3171 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3172 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3173 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3174 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3175
Prakash, Sathya436ace72007-07-24 15:42:08 +05303176 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303178 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 ioc->name, ioc->req_sz, ioc->req_depth));
3180
3181 /* Get port facts! */
3182 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3183 return r;
3184 }
3185 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003186 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3188 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3189 RequestFrameSize)/sizeof(u32)));
3190 return -66;
3191 }
3192
3193 return 0;
3194}
3195
3196/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003197/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198 * GetPortFacts - Send PortFacts request to MPT adapter.
3199 * @ioc: Pointer to MPT_ADAPTER structure
3200 * @portnum: Port number
3201 * @sleepFlag: Specifies whether the process can sleep
3202 *
3203 * Returns 0 for success, non-zero for failure.
3204 */
3205static int
3206GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3207{
3208 PortFacts_t get_pfacts;
3209 PortFactsReply_t *pfacts;
3210 int ii;
3211 int req_sz;
3212 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003213 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214
3215 /* IOC *must* NOT be in RESET state! */
3216 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003217 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3218 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 return -4;
3220 }
3221
3222 pfacts = &ioc->pfacts[portnum];
3223
3224 /* Destination (reply area)... */
3225 reply_sz = sizeof(*pfacts);
3226 memset(pfacts, 0, reply_sz);
3227
3228 /* Request area (get_pfacts on the stack right now!) */
3229 req_sz = sizeof(get_pfacts);
3230 memset(&get_pfacts, 0, req_sz);
3231
3232 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3233 get_pfacts.PortNumber = portnum;
3234 /* Assert: All other get_pfacts fields are zero! */
3235
Prakash, Sathya436ace72007-07-24 15:42:08 +05303236 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 ioc->name, portnum));
3238
3239 /* No non-zero fields in the get_pfacts request are greater than
3240 * 1 byte in size, so we can just fire it off as is.
3241 */
3242 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3243 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3244 if (ii != 0)
3245 return ii;
3246
3247 /* Did we get a valid reply? */
3248
3249 /* Now byte swap the necessary fields in the response. */
3250 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3251 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3252 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3253 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3254 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3255 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3256 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3257 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3258 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3259
Eric Moore793955f2007-01-29 09:42:20 -07003260 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3261 pfacts->MaxDevices;
3262 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3263 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3264
3265 /*
3266 * Place all the devices on channels
3267 *
3268 * (for debuging)
3269 */
3270 if (mpt_channel_mapping) {
3271 ioc->devices_per_bus = 1;
3272 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3273 }
3274
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 return 0;
3276}
3277
3278/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003279/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 * SendIocInit - Send IOCInit request to MPT adapter.
3281 * @ioc: Pointer to MPT_ADAPTER structure
3282 * @sleepFlag: Specifies whether the process can sleep
3283 *
3284 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3285 *
3286 * Returns 0 for success, non-zero for failure.
3287 */
3288static int
3289SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3290{
3291 IOCInit_t ioc_init;
3292 MPIDefaultReply_t init_reply;
3293 u32 state;
3294 int r;
3295 int count;
3296 int cntdn;
3297
3298 memset(&ioc_init, 0, sizeof(ioc_init));
3299 memset(&init_reply, 0, sizeof(init_reply));
3300
3301 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3302 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3303
3304 /* If we are in a recovery mode and we uploaded the FW image,
3305 * then this pointer is not NULL. Skip the upload a second time.
3306 * Set this flag if cached_fw set for either IOC.
3307 */
3308 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3309 ioc->upload_fw = 1;
3310 else
3311 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303312 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3314
Eric Moore793955f2007-01-29 09:42:20 -07003315 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3316 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303317
Prakash, Sathya436ace72007-07-24 15:42:08 +05303318 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003319 ioc->name, ioc->facts.MsgVersion));
3320 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3321 // set MsgVersion and HeaderVersion host driver was built with
3322 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3323 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003325 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3326 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3327 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3328 return -99;
3329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3331
Kashyap, Desai2f187862009-05-29 16:52:37 +05303332 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 /* Save the upper 32-bits of the request
3334 * (reply) and sense buffers.
3335 */
3336 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3337 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3338 } else {
3339 /* Force 32-bit addressing */
3340 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3341 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3342 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003343
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3345 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003346 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3347 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348
Prakash, Sathya436ace72007-07-24 15:42:08 +05303349 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350 ioc->name, &ioc_init));
3351
3352 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3353 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003354 if (r != 0) {
3355 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003357 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358
3359 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003360 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361 */
3362
Prakash, Sathya436ace72007-07-24 15:42:08 +05303363 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003365
3366 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3367 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003369 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370
3371 /* YIKES! SUPER IMPORTANT!!!
3372 * Poll IocState until _OPERATIONAL while IOC is doing
3373 * LoopInit and TargetDiscovery!
3374 */
3375 count = 0;
3376 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3377 state = mpt_GetIocState(ioc, 1);
3378 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3379 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003380 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 } else {
3382 mdelay(1);
3383 }
3384
3385 if (!cntdn) {
3386 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3387 ioc->name, (int)((count+5)/HZ));
3388 return -9;
3389 }
3390
3391 state = mpt_GetIocState(ioc, 1);
3392 count++;
3393 }
Eric Moore29dd3602007-09-14 18:46:51 -06003394 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395 ioc->name, count));
3396
Eric Mooreba856d32006-07-11 17:34:01 -06003397 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398 return r;
3399}
3400
3401/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003402/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 * SendPortEnable - Send PortEnable request to MPT adapter port.
3404 * @ioc: Pointer to MPT_ADAPTER structure
3405 * @portnum: Port number to enable
3406 * @sleepFlag: Specifies whether the process can sleep
3407 *
3408 * Send PortEnable to bring IOC to OPERATIONAL state.
3409 *
3410 * Returns 0 for success, non-zero for failure.
3411 */
3412static int
3413SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3414{
3415 PortEnable_t port_enable;
3416 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003417 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 int req_sz;
3419 int reply_sz;
3420
3421 /* Destination... */
3422 reply_sz = sizeof(MPIDefaultReply_t);
3423 memset(&reply_buf, 0, reply_sz);
3424
3425 req_sz = sizeof(PortEnable_t);
3426 memset(&port_enable, 0, req_sz);
3427
3428 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3429 port_enable.PortNumber = portnum;
3430/* port_enable.ChainOffset = 0; */
3431/* port_enable.MsgFlags = 0; */
3432/* port_enable.MsgContext = 0; */
3433
Prakash, Sathya436ace72007-07-24 15:42:08 +05303434 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 ioc->name, portnum, &port_enable));
3436
3437 /* RAID FW may take a long time to enable
3438 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003439 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003440 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3441 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3442 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003443 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003444 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3445 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3446 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003448 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449}
3450
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003451/**
3452 * mpt_alloc_fw_memory - allocate firmware memory
3453 * @ioc: Pointer to MPT_ADAPTER structure
3454 * @size: total FW bytes
3455 *
3456 * If memory has already been allocated, the same (cached) value
3457 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303458 *
3459 * Return 0 if successfull, or non-zero for failure
3460 **/
3461int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3463{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303464 int rc;
3465
3466 if (ioc->cached_fw) {
3467 rc = 0; /* use already allocated memory */
3468 goto out;
3469 }
3470 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3472 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303473 rc = 0;
3474 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303476 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3477 if (!ioc->cached_fw) {
3478 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3479 ioc->name);
3480 rc = -1;
3481 } else {
3482 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3483 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3484 ioc->alloc_total += size;
3485 rc = 0;
3486 }
3487 out:
3488 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303490
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003491/**
3492 * mpt_free_fw_memory - free firmware memory
3493 * @ioc: Pointer to MPT_ADAPTER structure
3494 *
3495 * If alt_img is NULL, delete from ioc structure.
3496 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303497 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498void
3499mpt_free_fw_memory(MPT_ADAPTER *ioc)
3500{
3501 int sz;
3502
Prakash, Sathya984621b2008-01-11 14:42:17 +05303503 if (!ioc->cached_fw)
3504 return;
3505
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303507 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3508 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003509 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303510 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512}
3513
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003515/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3517 * @ioc: Pointer to MPT_ADAPTER structure
3518 * @sleepFlag: Specifies whether the process can sleep
3519 *
3520 * Returns 0 for success, >0 for handshake failure
3521 * <0 for fw upload failure.
3522 *
3523 * Remark: If bound IOC and a successful FWUpload was performed
3524 * on the bound IOC, the second image is discarded
3525 * and memory is free'd. Both channels must upload to prevent
3526 * IOC from running in degraded mode.
3527 */
3528static int
3529mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3530{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 u8 reply[sizeof(FWUploadReply_t)];
3532 FWUpload_t *prequest;
3533 FWUploadReply_t *preply;
3534 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 u32 flagsLength;
3536 int ii, sz, reply_sz;
3537 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303538 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539 /* If the image size is 0, we are done.
3540 */
3541 if ((sz = ioc->facts.FWImageSize) == 0)
3542 return 0;
3543
Prakash, Sathya984621b2008-01-11 14:42:17 +05303544 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3545 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546
Eric Moore29dd3602007-09-14 18:46:51 -06003547 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3548 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003549
Eric Moorebc6e0892007-09-29 10:16:28 -06003550 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3551 kzalloc(ioc->req_sz, GFP_KERNEL);
3552 if (!prequest) {
3553 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3554 "while allocating memory \n", ioc->name));
3555 mpt_free_fw_memory(ioc);
3556 return -ENOMEM;
3557 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558
Eric Moorebc6e0892007-09-29 10:16:28 -06003559 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560
3561 reply_sz = sizeof(reply);
3562 memset(preply, 0, reply_sz);
3563
3564 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3565 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3566
3567 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3568 ptcsge->DetailsLength = 12;
3569 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3570 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003571 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303574 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3575 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3576 ioc->SGE_size;
3577 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3578 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3579 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003580 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303582 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3583 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584
Kashyap, Desai2f187862009-05-29 16:52:37 +05303585 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
3586 "rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587
3588 cmdStatus = -EFAULT;
3589 if (ii == 0) {
3590 /* Handshake transfer was complete and successful.
3591 * Check the Reply Frame.
3592 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303593 int status;
3594 status = le16_to_cpu(preply->IOCStatus) &
3595 MPI_IOCSTATUS_MASK;
3596 if (status == MPI_IOCSTATUS_SUCCESS &&
3597 ioc->facts.FWImageSize ==
3598 le32_to_cpu(preply->ActualImageSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 cmdStatus = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303601 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 ioc->name, cmdStatus));
3603
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003604
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 if (cmdStatus) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303606 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
3607 "freeing image \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 mpt_free_fw_memory(ioc);
3609 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003610 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611
3612 return cmdStatus;
3613}
3614
3615/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003616/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 * mpt_downloadboot - DownloadBoot code
3618 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003619 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 * @sleepFlag: Specifies whether the process can sleep
3621 *
3622 * FwDownloadBoot requires Programmed IO access.
3623 *
3624 * Returns 0 for success
3625 * -1 FW Image size is 0
3626 * -2 No valid cached_fw Pointer
3627 * <0 for fw upload failure.
3628 */
3629static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003630mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632 MpiExtImageHeader_t *pExtImage;
3633 u32 fwSize;
3634 u32 diag0val;
3635 int count;
3636 u32 *ptrFw;
3637 u32 diagRwData;
3638 u32 nextImage;
3639 u32 load_addr;
3640 u32 ioc_state=0;
3641
Prakash, Sathya436ace72007-07-24 15:42:08 +05303642 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003643 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003644
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3646 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3647 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3648 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3649 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3650 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3651
3652 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3653
3654 /* wait 1 msec */
3655 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003656 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 } else {
3658 mdelay (1);
3659 }
3660
3661 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3662 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3663
3664 for (count = 0; count < 30; count ++) {
3665 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3666 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303667 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 ioc->name, count));
3669 break;
3670 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003671 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003673 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003675 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 }
3677 }
3678
3679 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303680 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003681 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682 ioc->name, diag0val));
3683 return -3;
3684 }
3685
3686 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3687 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3688 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3689 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3690 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3691 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3692
3693 /* Set the DiagRwEn and Disable ARM bits */
3694 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3695
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696 fwSize = (pFwHeader->ImageSize + 3)/4;
3697 ptrFw = (u32 *) pFwHeader;
3698
3699 /* Write the LoadStartAddress to the DiagRw Address Register
3700 * using Programmed IO
3701 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003702 if (ioc->errata_flag_1064)
3703 pci_enable_io_access(ioc->pcidev);
3704
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303706 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 ioc->name, pFwHeader->LoadStartAddress));
3708
Prakash, Sathya436ace72007-07-24 15:42:08 +05303709 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710 ioc->name, fwSize*4, ptrFw));
3711 while (fwSize--) {
3712 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3713 }
3714
3715 nextImage = pFwHeader->NextImageHeaderOffset;
3716 while (nextImage) {
3717 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3718
3719 load_addr = pExtImage->LoadStartAddress;
3720
3721 fwSize = (pExtImage->ImageSize + 3) >> 2;
3722 ptrFw = (u32 *)pExtImage;
3723
Prakash, Sathya436ace72007-07-24 15:42:08 +05303724 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 +02003725 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3727
3728 while (fwSize--) {
3729 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3730 }
3731 nextImage = pExtImage->NextImageHeaderOffset;
3732 }
3733
3734 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303735 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3737
3738 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303739 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3741
3742 /* Clear the internal flash bad bit - autoincrementing register,
3743 * so must do two writes.
3744 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003745 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003746 /*
3747 * 1030 and 1035 H/W errata, workaround to access
3748 * the ClearFlashBadSignatureBit
3749 */
3750 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3751 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3752 diagRwData |= 0x40000000;
3753 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3754 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3755
3756 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3757 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3758 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3759 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3760
3761 /* wait 1 msec */
3762 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003763 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003764 } else {
3765 mdelay (1);
3766 }
3767 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003769 if (ioc->errata_flag_1064)
3770 pci_disable_io_access(ioc->pcidev);
3771
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303773 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003774 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003776 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303777 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778 ioc->name, diag0val));
3779 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3780
3781 /* Write 0xFF to reset the sequencer */
3782 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3783
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003784 if (ioc->bus_type == SAS) {
3785 ioc_state = mpt_GetIocState(ioc, 0);
3786 if ( (GetIocFacts(ioc, sleepFlag,
3787 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303788 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003789 ioc->name, ioc_state));
3790 return -EFAULT;
3791 }
3792 }
3793
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 for (count=0; count<HZ*20; count++) {
3795 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303796 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3797 "downloadboot successful! (count=%d) IocState=%x\n",
3798 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003799 if (ioc->bus_type == SAS) {
3800 return 0;
3801 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003802 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303803 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3804 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805 ioc->name));
3806 return -EFAULT;
3807 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303808 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3809 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810 ioc->name));
3811 return 0;
3812 }
3813 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003814 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 } else {
3816 mdelay (10);
3817 }
3818 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303819 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3820 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 return -EFAULT;
3822}
3823
3824/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003825/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826 * KickStart - Perform hard reset of MPT adapter.
3827 * @ioc: Pointer to MPT_ADAPTER structure
3828 * @force: Force hard reset
3829 * @sleepFlag: Specifies whether the process can sleep
3830 *
3831 * This routine places MPT adapter in diagnostic mode via the
3832 * WriteSequence register, and then performs a hard reset of adapter
3833 * via the Diagnostic register.
3834 *
3835 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3836 * or NO_SLEEP (interrupt thread, use mdelay)
3837 * force - 1 if doorbell active, board fault state
3838 * board operational, IOC_RECOVERY or
3839 * IOC_BRINGUP and there is an alt_ioc.
3840 * 0 else
3841 *
3842 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003843 * 1 - hard reset, READY
3844 * 0 - no reset due to History bit, READY
3845 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846 * OR reset but failed to come READY
3847 * -2 - no reset, could not enter DIAG mode
3848 * -3 - reset but bad FW bit
3849 */
3850static int
3851KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3852{
3853 int hard_reset_done = 0;
3854 u32 ioc_state=0;
3855 int cnt,cntdn;
3856
Eric Moore29dd3602007-09-14 18:46:51 -06003857 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003858 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859 /* Always issue a Msg Unit Reset first. This will clear some
3860 * SCSI bus hang conditions.
3861 */
3862 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3863
3864 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003865 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 } else {
3867 mdelay (1000);
3868 }
3869 }
3870
3871 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3872 if (hard_reset_done < 0)
3873 return hard_reset_done;
3874
Prakash, Sathya436ace72007-07-24 15:42:08 +05303875 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003876 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877
3878 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3879 for (cnt=0; cnt<cntdn; cnt++) {
3880 ioc_state = mpt_GetIocState(ioc, 1);
3881 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303882 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883 ioc->name, cnt));
3884 return hard_reset_done;
3885 }
3886 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003887 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 } else {
3889 mdelay (10);
3890 }
3891 }
3892
Eric Moore29dd3602007-09-14 18:46:51 -06003893 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3894 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 return -1;
3896}
3897
3898/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003899/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 * mpt_diag_reset - Perform hard reset of the adapter.
3901 * @ioc: Pointer to MPT_ADAPTER structure
3902 * @ignore: Set if to honor and clear to ignore
3903 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003904 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 * else set to NO_SLEEP (use mdelay instead)
3906 *
3907 * This routine places the adapter in diagnostic mode via the
3908 * WriteSequence register and then performs a hard reset of adapter
3909 * via the Diagnostic register. Adapter should be in ready state
3910 * upon successful completion.
3911 *
3912 * Returns: 1 hard reset successful
3913 * 0 no reset performed because reset history bit set
3914 * -2 enabling diagnostic mode failed
3915 * -3 diagnostic reset failed
3916 */
3917static int
3918mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3919{
3920 u32 diag0val;
3921 u32 doorbell;
3922 int hard_reset_done = 0;
3923 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303925 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926
Eric Moorecd2c6192007-01-29 09:47:47 -07003927 /* Clear any existing interrupts */
3928 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3929
Eric Moore87cf8982006-06-27 16:09:26 -06003930 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303931
3932 if (!ignore)
3933 return 0;
3934
Prakash, Sathya436ace72007-07-24 15:42:08 +05303935 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003936 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003937 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3938 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3939 if (sleepFlag == CAN_SLEEP)
3940 msleep(1);
3941 else
3942 mdelay(1);
3943
3944 for (count = 0; count < 60; count ++) {
3945 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3946 doorbell &= MPI_IOC_STATE_MASK;
3947
Prakash, Sathya436ace72007-07-24 15:42:08 +05303948 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003949 "looking for READY STATE: doorbell=%x"
3950 " count=%d\n",
3951 ioc->name, doorbell, count));
Kashyap, Desai2f187862009-05-29 16:52:37 +05303952
Eric Moore87cf8982006-06-27 16:09:26 -06003953 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003954 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003955 }
3956
3957 /* wait 1 sec */
3958 if (sleepFlag == CAN_SLEEP)
3959 msleep(1000);
3960 else
3961 mdelay(1000);
3962 }
3963 return -1;
3964 }
3965
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 /* Use "Diagnostic reset" method! (only thing available!) */
3967 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3968
Prakash, Sathya436ace72007-07-24 15:42:08 +05303969 if (ioc->debug_level & MPT_DEBUG) {
3970 if (ioc->alt_ioc)
3971 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3972 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303974 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975
3976 /* Do the reset if we are told to ignore the reset history
3977 * or if the reset history is 0
3978 */
3979 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3980 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3981 /* Write magic sequence to WriteSequence register
3982 * Loop until in diagnostic mode
3983 */
3984 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3985 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3986 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3987 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3988 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3989 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3990
3991 /* wait 100 msec */
3992 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003993 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 } else {
3995 mdelay (100);
3996 }
3997
3998 count++;
3999 if (count > 20) {
4000 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4001 ioc->name, diag0val);
4002 return -2;
4003
4004 }
4005
4006 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4007
Prakash, Sathya436ace72007-07-24 15:42:08 +05304008 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 ioc->name, diag0val));
4010 }
4011
Prakash, Sathya436ace72007-07-24 15:42:08 +05304012 if (ioc->debug_level & MPT_DEBUG) {
4013 if (ioc->alt_ioc)
4014 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4015 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304017 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 /*
4019 * Disable the ARM (Bug fix)
4020 *
4021 */
4022 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004023 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024
4025 /*
4026 * Now hit the reset bit in the Diagnostic register
4027 * (THE BIG HAMMER!) (Clears DRWE bit).
4028 */
4029 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
4030 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304031 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 ioc->name));
4033
4034 /*
4035 * Call each currently registered protocol IOC reset handler
4036 * with pre-reset indication.
4037 * NOTE: If we're doing _IOC_BRINGUP, there can be no
4038 * MptResetHandlers[] registered yet.
4039 */
4040 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304041 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042 int r = 0;
4043
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304044 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
4045 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304046 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4047 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304048 ioc->name, cb_idx));
4049 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304051 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4052 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304053 ioc->name, ioc->alt_ioc->name, cb_idx));
4054 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055 }
4056 }
4057 }
4058 /* FIXME? Examine results here? */
4059 }
4060
Eric Moore0ccdb002006-07-11 17:33:13 -06004061 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304062 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06004063 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304064 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4065 else
4066 cached_fw = NULL;
4067 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 /* If the DownloadBoot operation fails, the
4069 * IOC will be left unusable. This is a fatal error
4070 * case. _diag_reset will return < 0
4071 */
4072 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304073 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4075 break;
4076 }
4077
Prakash, Sathya436ace72007-07-24 15:42:08 +05304078 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304079 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080 /* wait 1 sec */
4081 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004082 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083 } else {
4084 mdelay (1000);
4085 }
4086 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304087 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004088 printk(MYIOC_s_WARN_FMT
4089 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090 }
4091
4092 } else {
4093 /* Wait for FW to reload and for board
4094 * to go to the READY state.
4095 * Maximum wait is 60 seconds.
4096 * If fail, no error will check again
4097 * with calling program.
4098 */
4099 for (count = 0; count < 60; count ++) {
4100 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4101 doorbell &= MPI_IOC_STATE_MASK;
4102
Kashyap, Desai2f187862009-05-29 16:52:37 +05304103 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4104 "looking for READY STATE: doorbell=%x"
4105 " count=%d\n", ioc->name, doorbell, count));
4106
Linus Torvalds1da177e2005-04-16 15:20:36 -07004107 if (doorbell == MPI_IOC_STATE_READY) {
4108 break;
4109 }
4110
4111 /* wait 1 sec */
4112 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004113 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114 } else {
4115 mdelay (1000);
4116 }
4117 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05304118
4119 if (doorbell != MPI_IOC_STATE_READY)
4120 printk(MYIOC_s_ERR_FMT "Failed to come READY "
4121 "after reset! IocState=%x", ioc->name,
4122 doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123 }
4124 }
4125
4126 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304127 if (ioc->debug_level & MPT_DEBUG) {
4128 if (ioc->alt_ioc)
4129 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4130 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4131 ioc->name, diag0val, diag1val));
4132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133
4134 /* Clear RESET_HISTORY bit! Place board in the
4135 * diagnostic mode to update the diag register.
4136 */
4137 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4138 count = 0;
4139 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4140 /* Write magic sequence to WriteSequence register
4141 * Loop until in diagnostic mode
4142 */
4143 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4144 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4145 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4146 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4147 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4148 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4149
4150 /* wait 100 msec */
4151 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004152 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153 } else {
4154 mdelay (100);
4155 }
4156
4157 count++;
4158 if (count > 20) {
4159 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4160 ioc->name, diag0val);
4161 break;
4162 }
4163 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4164 }
4165 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4166 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4167 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4168 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4169 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4170 ioc->name);
4171 }
4172
4173 /* Disable Diagnostic Mode
4174 */
4175 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4176
4177 /* Check FW reload status flags.
4178 */
4179 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4180 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4181 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4182 ioc->name, diag0val);
4183 return -3;
4184 }
4185
Prakash, Sathya436ace72007-07-24 15:42:08 +05304186 if (ioc->debug_level & MPT_DEBUG) {
4187 if (ioc->alt_ioc)
4188 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4189 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304191 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192
4193 /*
4194 * Reset flag that says we've enabled event notification
4195 */
4196 ioc->facts.EventState = 0;
4197
4198 if (ioc->alt_ioc)
4199 ioc->alt_ioc->facts.EventState = 0;
4200
4201 return hard_reset_done;
4202}
4203
4204/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004205/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 * SendIocReset - Send IOCReset request to MPT adapter.
4207 * @ioc: Pointer to MPT_ADAPTER structure
4208 * @reset_type: reset type, expected values are
4209 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004210 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211 *
4212 * Send IOCReset request to the MPT adapter.
4213 *
4214 * Returns 0 for success, non-zero for failure.
4215 */
4216static int
4217SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4218{
4219 int r;
4220 u32 state;
4221 int cntdn, count;
4222
Prakash, Sathya436ace72007-07-24 15:42:08 +05304223 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224 ioc->name, reset_type));
4225 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4226 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4227 return r;
4228
4229 /* FW ACK'd request, wait for READY state
4230 */
4231 count = 0;
4232 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4233
4234 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4235 cntdn--;
4236 count++;
4237 if (!cntdn) {
4238 if (sleepFlag != CAN_SLEEP)
4239 count *= 10;
4240
Kashyap, Desai2f187862009-05-29 16:52:37 +05304241 printk(MYIOC_s_ERR_FMT
4242 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
4243 ioc->name, state, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244 return -ETIME;
4245 }
4246
4247 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004248 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249 } else {
4250 mdelay (1); /* 1 msec delay */
4251 }
4252 }
4253
4254 /* TODO!
4255 * Cleanup all event stuff for this IOC; re-issue EventNotification
4256 * request if needed.
4257 */
4258 if (ioc->facts.Function)
4259 ioc->facts.EventState = 0;
4260
4261 return 0;
4262}
4263
4264/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004265/**
4266 * initChainBuffers - Allocate memory for and initialize chain buffers
4267 * @ioc: Pointer to MPT_ADAPTER structure
4268 *
4269 * Allocates memory for and initializes chain buffers,
4270 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271 */
4272static int
4273initChainBuffers(MPT_ADAPTER *ioc)
4274{
4275 u8 *mem;
4276 int sz, ii, num_chain;
4277 int scale, num_sge, numSGE;
4278
4279 /* ReqToChain size must equal the req_depth
4280 * index = req_idx
4281 */
4282 if (ioc->ReqToChain == NULL) {
4283 sz = ioc->req_depth * sizeof(int);
4284 mem = kmalloc(sz, GFP_ATOMIC);
4285 if (mem == NULL)
4286 return -1;
4287
4288 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304289 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290 ioc->name, mem, sz));
4291 mem = kmalloc(sz, GFP_ATOMIC);
4292 if (mem == NULL)
4293 return -1;
4294
4295 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304296 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297 ioc->name, mem, sz));
4298 }
4299 for (ii = 0; ii < ioc->req_depth; ii++) {
4300 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4301 }
4302
4303 /* ChainToChain size must equal the total number
4304 * of chain buffers to be allocated.
4305 * index = chain_idx
4306 *
4307 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004308 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309 *
4310 * num_sge = num sge in request frame + last chain buffer
4311 * scale = num sge per chain buffer if no chain element
4312 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304313 scale = ioc->req_sz / ioc->SGE_size;
4314 if (ioc->sg_addr_size == sizeof(u64))
4315 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304317 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304319 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304321 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304323 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4324 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304326 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327 ioc->name, num_sge, numSGE));
4328
Kashyap, Desai2f187862009-05-29 16:52:37 +05304329 if (ioc->bus_type == FC) {
4330 if (numSGE > MPT_SCSI_FC_SG_DEPTH)
4331 numSGE = MPT_SCSI_FC_SG_DEPTH;
4332 } else {
4333 if (numSGE > MPT_SCSI_SG_DEPTH)
4334 numSGE = MPT_SCSI_SG_DEPTH;
4335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336
4337 num_chain = 1;
4338 while (numSGE - num_sge > 0) {
4339 num_chain++;
4340 num_sge += (scale - 1);
4341 }
4342 num_chain++;
4343
Prakash, Sathya436ace72007-07-24 15:42:08 +05304344 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 ioc->name, numSGE, num_sge, num_chain));
4346
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004347 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348 num_chain *= MPT_SCSI_CAN_QUEUE;
4349 else
4350 num_chain *= MPT_FC_CAN_QUEUE;
4351
4352 ioc->num_chain = num_chain;
4353
4354 sz = num_chain * sizeof(int);
4355 if (ioc->ChainToChain == NULL) {
4356 mem = kmalloc(sz, GFP_ATOMIC);
4357 if (mem == NULL)
4358 return -1;
4359
4360 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304361 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362 ioc->name, mem, sz));
4363 } else {
4364 mem = (u8 *) ioc->ChainToChain;
4365 }
4366 memset(mem, 0xFF, sz);
4367 return num_chain;
4368}
4369
4370/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004371/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4373 * @ioc: Pointer to MPT_ADAPTER structure
4374 *
4375 * This routine allocates memory for the MPT reply and request frame
4376 * pools (if necessary), and primes the IOC reply FIFO with
4377 * reply frames.
4378 *
4379 * Returns 0 for success, non-zero for failure.
4380 */
4381static int
4382PrimeIocFifos(MPT_ADAPTER *ioc)
4383{
4384 MPT_FRAME_HDR *mf;
4385 unsigned long flags;
4386 dma_addr_t alloc_dma;
4387 u8 *mem;
4388 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304389 u64 dma_mask;
4390
4391 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392
4393 /* Prime reply FIFO... */
4394
4395 if (ioc->reply_frames == NULL) {
4396 if ( (num_chain = initChainBuffers(ioc)) < 0)
4397 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304398 /*
4399 * 1078 errata workaround for the 36GB limitation
4400 */
4401 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
4402 ioc->dma_mask > DMA_35BIT_MASK) {
4403 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4404 && !pci_set_consistent_dma_mask(ioc->pcidev,
4405 DMA_BIT_MASK(32))) {
4406 dma_mask = DMA_35BIT_MASK;
4407 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4408 "setting 35 bit addressing for "
4409 "Request/Reply/Chain and Sense Buffers\n",
4410 ioc->name));
4411 } else {
4412 /*Reseting DMA mask to 64 bit*/
4413 pci_set_dma_mask(ioc->pcidev,
4414 DMA_BIT_MASK(64));
4415 pci_set_consistent_dma_mask(ioc->pcidev,
4416 DMA_BIT_MASK(64));
4417
4418 printk(MYIOC_s_ERR_FMT
4419 "failed setting 35 bit addressing for "
4420 "Request/Reply/Chain and Sense Buffers\n",
4421 ioc->name);
4422 return -1;
4423 }
4424 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425
4426 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304427 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304429 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 ioc->name, reply_sz, reply_sz));
4431
4432 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304433 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304435 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436 ioc->name, sz, sz));
4437 total_size += sz;
4438
4439 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304440 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304442 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 ioc->name, sz, sz, num_chain));
4444
4445 total_size += sz;
4446 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4447 if (mem == NULL) {
4448 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4449 ioc->name);
4450 goto out_fail;
4451 }
4452
Prakash, Sathya436ace72007-07-24 15:42:08 +05304453 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4455
4456 memset(mem, 0, total_size);
4457 ioc->alloc_total += total_size;
4458 ioc->alloc = mem;
4459 ioc->alloc_dma = alloc_dma;
4460 ioc->alloc_sz = total_size;
4461 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4462 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4463
Prakash, Sathya436ace72007-07-24 15:42:08 +05304464 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004465 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4466
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467 alloc_dma += reply_sz;
4468 mem += reply_sz;
4469
4470 /* Request FIFO - WE manage this! */
4471
4472 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4473 ioc->req_frames_dma = alloc_dma;
4474
Prakash, Sathya436ace72007-07-24 15:42:08 +05304475 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 ioc->name, mem, (void *)(ulong)alloc_dma));
4477
4478 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4479
4480#if defined(CONFIG_MTRR) && 0
4481 /*
4482 * Enable Write Combining MTRR for IOC's memory region.
4483 * (at least as much as we can; "size and base must be
4484 * multiples of 4 kiB"
4485 */
4486 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4487 sz,
4488 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304489 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 ioc->name, ioc->req_frames_dma, sz));
4491#endif
4492
4493 for (i = 0; i < ioc->req_depth; i++) {
4494 alloc_dma += ioc->req_sz;
4495 mem += ioc->req_sz;
4496 }
4497
4498 ioc->ChainBuffer = mem;
4499 ioc->ChainBufferDMA = alloc_dma;
4500
Prakash, Sathya436ace72007-07-24 15:42:08 +05304501 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4503
4504 /* Initialize the free chain Q.
4505 */
4506
4507 INIT_LIST_HEAD(&ioc->FreeChainQ);
4508
4509 /* Post the chain buffers to the FreeChainQ.
4510 */
4511 mem = (u8 *)ioc->ChainBuffer;
4512 for (i=0; i < num_chain; i++) {
4513 mf = (MPT_FRAME_HDR *) mem;
4514 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4515 mem += ioc->req_sz;
4516 }
4517
4518 /* Initialize Request frames linked list
4519 */
4520 alloc_dma = ioc->req_frames_dma;
4521 mem = (u8 *) ioc->req_frames;
4522
4523 spin_lock_irqsave(&ioc->FreeQlock, flags);
4524 INIT_LIST_HEAD(&ioc->FreeQ);
4525 for (i = 0; i < ioc->req_depth; i++) {
4526 mf = (MPT_FRAME_HDR *) mem;
4527
4528 /* Queue REQUESTs *internally*! */
4529 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4530
4531 mem += ioc->req_sz;
4532 }
4533 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4534
4535 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4536 ioc->sense_buf_pool =
4537 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4538 if (ioc->sense_buf_pool == NULL) {
4539 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4540 ioc->name);
4541 goto out_fail;
4542 }
4543
4544 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4545 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304546 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4548
4549 }
4550
4551 /* Post Reply frames to FIFO
4552 */
4553 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304554 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4556
4557 for (i = 0; i < ioc->reply_depth; i++) {
4558 /* Write each address to the IOC! */
4559 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4560 alloc_dma += ioc->reply_sz;
4561 }
4562
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304563 if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
4564 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4565 ioc->dma_mask))
4566 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4567 "restoring 64 bit addressing\n", ioc->name));
4568
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 return 0;
4570
4571out_fail:
Kashyap, Desai2f187862009-05-29 16:52:37 +05304572
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 if (ioc->alloc != NULL) {
4574 sz = ioc->alloc_sz;
4575 pci_free_consistent(ioc->pcidev,
4576 sz,
4577 ioc->alloc, ioc->alloc_dma);
4578 ioc->reply_frames = NULL;
4579 ioc->req_frames = NULL;
4580 ioc->alloc_total -= sz;
4581 }
4582 if (ioc->sense_buf_pool != NULL) {
4583 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4584 pci_free_consistent(ioc->pcidev,
4585 sz,
4586 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4587 ioc->sense_buf_pool = NULL;
4588 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304589
4590 if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
4591 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4592 DMA_BIT_MASK(64)))
4593 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4594 "restoring 64 bit addressing\n", ioc->name));
4595
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 return -1;
4597}
4598
4599/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4600/**
4601 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4602 * from IOC via doorbell handshake method.
4603 * @ioc: Pointer to MPT_ADAPTER structure
4604 * @reqBytes: Size of the request in bytes
4605 * @req: Pointer to MPT request frame
4606 * @replyBytes: Expected size of the reply in bytes
4607 * @u16reply: Pointer to area where reply should be written
4608 * @maxwait: Max wait time for a reply (in seconds)
4609 * @sleepFlag: Specifies whether the process can sleep
4610 *
4611 * NOTES: It is the callers responsibility to byte-swap fields in the
4612 * request which are greater than 1 byte in size. It is also the
4613 * callers responsibility to byte-swap response fields which are
4614 * greater than 1 byte in size.
4615 *
4616 * Returns 0 for success, non-zero for failure.
4617 */
4618static int
4619mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004620 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621{
4622 MPIDefaultReply_t *mptReply;
4623 int failcnt = 0;
4624 int t;
4625
4626 /*
4627 * Get ready to cache a handshake reply
4628 */
4629 ioc->hs_reply_idx = 0;
4630 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4631 mptReply->MsgLength = 0;
4632
4633 /*
4634 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4635 * then tell IOC that we want to handshake a request of N words.
4636 * (WRITE u32val to Doorbell reg).
4637 */
4638 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4639 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4640 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4641 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4642
4643 /*
4644 * Wait for IOC's doorbell handshake int
4645 */
4646 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4647 failcnt++;
4648
Prakash, Sathya436ace72007-07-24 15:42:08 +05304649 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4651
4652 /* Read doorbell and check for active bit */
4653 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4654 return -1;
4655
4656 /*
4657 * Clear doorbell int (WRITE 0 to IntStatus reg),
4658 * then wait for IOC to ACKnowledge that it's ready for
4659 * our handshake request.
4660 */
4661 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4662 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4663 failcnt++;
4664
4665 if (!failcnt) {
4666 int ii;
4667 u8 *req_as_bytes = (u8 *) req;
4668
4669 /*
4670 * Stuff request words via doorbell handshake,
4671 * with ACK from IOC for each.
4672 */
4673 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4674 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4675 (req_as_bytes[(ii*4) + 1] << 8) |
4676 (req_as_bytes[(ii*4) + 2] << 16) |
4677 (req_as_bytes[(ii*4) + 3] << 24));
4678
4679 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4680 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4681 failcnt++;
4682 }
4683
Prakash, Sathya436ace72007-07-24 15:42:08 +05304684 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004685 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686
Prakash, Sathya436ace72007-07-24 15:42:08 +05304687 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4689
4690 /*
4691 * Wait for completion of doorbell handshake reply from the IOC
4692 */
4693 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4694 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004695
Prakash, Sathya436ace72007-07-24 15:42:08 +05304696 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4698
4699 /*
4700 * Copy out the cached reply...
4701 */
4702 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4703 u16reply[ii] = ioc->hs_reply[ii];
4704 } else {
4705 return -99;
4706 }
4707
4708 return -failcnt;
4709}
4710
4711/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004712/**
4713 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714 * @ioc: Pointer to MPT_ADAPTER structure
4715 * @howlong: How long to wait (in seconds)
4716 * @sleepFlag: Specifies whether the process can sleep
4717 *
4718 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004719 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4720 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 *
4722 * Returns a negative value on failure, else wait loop count.
4723 */
4724static int
4725WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4726{
4727 int cntdn;
4728 int count = 0;
4729 u32 intstat=0;
4730
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004731 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732
4733 if (sleepFlag == CAN_SLEEP) {
4734 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004735 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4737 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4738 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739 count++;
4740 }
4741 } else {
4742 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004743 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4745 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4746 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 count++;
4748 }
4749 }
4750
4751 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304752 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753 ioc->name, count));
4754 return count;
4755 }
4756
4757 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4758 ioc->name, count, intstat);
4759 return -1;
4760}
4761
4762/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004763/**
4764 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 * @ioc: Pointer to MPT_ADAPTER structure
4766 * @howlong: How long to wait (in seconds)
4767 * @sleepFlag: Specifies whether the process can sleep
4768 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004769 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4770 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 *
4772 * Returns a negative value on failure, else wait loop count.
4773 */
4774static int
4775WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4776{
4777 int cntdn;
4778 int count = 0;
4779 u32 intstat=0;
4780
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004781 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 if (sleepFlag == CAN_SLEEP) {
4783 while (--cntdn) {
4784 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4785 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4786 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004787 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 count++;
4789 }
4790 } else {
4791 while (--cntdn) {
4792 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4793 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4794 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004795 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796 count++;
4797 }
4798 }
4799
4800 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304801 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 ioc->name, count, howlong));
4803 return count;
4804 }
4805
4806 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4807 ioc->name, count, intstat);
4808 return -1;
4809}
4810
4811/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004812/**
4813 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 * @ioc: Pointer to MPT_ADAPTER structure
4815 * @howlong: How long to wait (in seconds)
4816 * @sleepFlag: Specifies whether the process can sleep
4817 *
4818 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4819 * Reply is cached to IOC private area large enough to hold a maximum
4820 * of 128 bytes of reply data.
4821 *
4822 * Returns a negative value on failure, else size of reply in WORDS.
4823 */
4824static int
4825WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4826{
4827 int u16cnt = 0;
4828 int failcnt = 0;
4829 int t;
4830 u16 *hs_reply = ioc->hs_reply;
4831 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4832 u16 hword;
4833
4834 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4835
4836 /*
4837 * Get first two u16's so we can look at IOC's intended reply MsgLength
4838 */
4839 u16cnt=0;
4840 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4841 failcnt++;
4842 } else {
4843 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4844 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4845 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4846 failcnt++;
4847 else {
4848 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4849 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4850 }
4851 }
4852
Prakash, Sathya436ace72007-07-24 15:42:08 +05304853 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004854 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4856
4857 /*
4858 * If no error (and IOC said MsgLength is > 0), piece together
4859 * reply 16 bits at a time.
4860 */
4861 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4862 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4863 failcnt++;
4864 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4865 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004866 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867 hs_reply[u16cnt] = hword;
4868 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4869 }
4870
4871 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4872 failcnt++;
4873 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4874
4875 if (failcnt) {
4876 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4877 ioc->name);
4878 return -failcnt;
4879 }
4880#if 0
4881 else if (u16cnt != (2 * mptReply->MsgLength)) {
4882 return -101;
4883 }
4884 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4885 return -102;
4886 }
4887#endif
4888
Prakash, Sathya436ace72007-07-24 15:42:08 +05304889 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004890 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891
Prakash, Sathya436ace72007-07-24 15:42:08 +05304892 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 ioc->name, t, u16cnt/2));
4894 return u16cnt/2;
4895}
4896
4897/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004898/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004899 * GetLanConfigPages - Fetch LANConfig pages.
4900 * @ioc: Pointer to MPT_ADAPTER structure
4901 *
4902 * Return: 0 for success
4903 * -ENOMEM if no memory available
4904 * -EPERM if not allowed due to ISR context
4905 * -EAGAIN if no msg frames currently available
4906 * -EFAULT for non-successful reply or no reply (timeout)
4907 */
4908static int
4909GetLanConfigPages(MPT_ADAPTER *ioc)
4910{
4911 ConfigPageHeader_t hdr;
4912 CONFIGPARMS cfg;
4913 LANPage0_t *ppage0_alloc;
4914 dma_addr_t page0_dma;
4915 LANPage1_t *ppage1_alloc;
4916 dma_addr_t page1_dma;
4917 int rc = 0;
4918 int data_sz;
4919 int copy_sz;
4920
4921 /* Get LAN Page 0 header */
4922 hdr.PageVersion = 0;
4923 hdr.PageLength = 0;
4924 hdr.PageNumber = 0;
4925 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004926 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927 cfg.physAddr = -1;
4928 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4929 cfg.dir = 0;
4930 cfg.pageAddr = 0;
4931 cfg.timeout = 0;
4932
4933 if ((rc = mpt_config(ioc, &cfg)) != 0)
4934 return rc;
4935
4936 if (hdr.PageLength > 0) {
4937 data_sz = hdr.PageLength * 4;
4938 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4939 rc = -ENOMEM;
4940 if (ppage0_alloc) {
4941 memset((u8 *)ppage0_alloc, 0, data_sz);
4942 cfg.physAddr = page0_dma;
4943 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4944
4945 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4946 /* save the data */
4947 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4948 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4949
4950 }
4951
4952 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4953
4954 /* FIXME!
4955 * Normalize endianness of structure data,
4956 * by byte-swapping all > 1 byte fields!
4957 */
4958
4959 }
4960
4961 if (rc)
4962 return rc;
4963 }
4964
4965 /* Get LAN Page 1 header */
4966 hdr.PageVersion = 0;
4967 hdr.PageLength = 0;
4968 hdr.PageNumber = 1;
4969 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004970 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971 cfg.physAddr = -1;
4972 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4973 cfg.dir = 0;
4974 cfg.pageAddr = 0;
4975
4976 if ((rc = mpt_config(ioc, &cfg)) != 0)
4977 return rc;
4978
4979 if (hdr.PageLength == 0)
4980 return 0;
4981
4982 data_sz = hdr.PageLength * 4;
4983 rc = -ENOMEM;
4984 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4985 if (ppage1_alloc) {
4986 memset((u8 *)ppage1_alloc, 0, data_sz);
4987 cfg.physAddr = page1_dma;
4988 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4989
4990 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4991 /* save the data */
4992 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4993 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4994 }
4995
4996 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4997
4998 /* FIXME!
4999 * Normalize endianness of structure data,
5000 * by byte-swapping all > 1 byte fields!
5001 */
5002
5003 }
5004
5005 return rc;
5006}
5007
5008/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005009/**
5010 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005011 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005012 * @persist_opcode: see below
5013 *
5014 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
5015 * devices not currently present.
5016 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
5017 *
5018 * NOTE: Don't use not this function during interrupt time.
5019 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005020 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005021 */
5022
5023/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5024int
5025mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
5026{
5027 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
5028 SasIoUnitControlReply_t *sasIoUnitCntrReply;
5029 MPT_FRAME_HDR *mf = NULL;
5030 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305031 int ret = 0;
5032 unsigned long timeleft;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005033
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305034 mutex_lock(&ioc->mptbase_cmds.mutex);
5035
5036 /* init the internal cmd struct */
5037 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
5038 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005039
5040 /* insure garbage is not sent to fw */
5041 switch(persist_opcode) {
5042
5043 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
5044 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
5045 break;
5046
5047 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305048 ret = -1;
5049 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005050 }
5051
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305052 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
5053 __func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005054
5055 /* Get a MF for this command.
5056 */
5057 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305058 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
5059 ret = -1;
5060 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005061 }
5062
5063 mpi_hdr = (MPIHeader_t *) mf;
5064 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
5065 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
5066 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
5067 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
5068 sasIoUnitCntrReq->Operation = persist_opcode;
5069
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005070 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305071 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
5072 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
5073 ret = -ETIME;
5074 printk(KERN_DEBUG "%s: failed\n", __func__);
5075 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
5076 goto out;
5077 if (!timeleft) {
5078 printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n",
5079 ioc->name, __func__);
5080 mpt_HardResetHandler(ioc, CAN_SLEEP);
5081 mpt_free_msg_frame(ioc, mf);
5082 }
5083 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005084 }
5085
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305086 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
5087 ret = -1;
5088 goto out;
5089 }
5090
5091 sasIoUnitCntrReply =
5092 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5093 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5094 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5095 __func__, sasIoUnitCntrReply->IOCStatus,
5096 sasIoUnitCntrReply->IOCLogInfo);
5097 printk(KERN_DEBUG "%s: failed\n", __func__);
5098 ret = -1;
5099 } else
5100 printk(KERN_DEBUG "%s: success\n", __func__);
5101 out:
5102
5103 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5104 mutex_unlock(&ioc->mptbase_cmds.mutex);
5105 return ret;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005106}
5107
5108/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005109
5110static void
5111mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5112 MpiEventDataRaid_t * pRaidEventData)
5113{
5114 int volume;
5115 int reason;
5116 int disk;
5117 int status;
5118 int flags;
5119 int state;
5120
5121 volume = pRaidEventData->VolumeID;
5122 reason = pRaidEventData->ReasonCode;
5123 disk = pRaidEventData->PhysDiskNum;
5124 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5125 flags = (status >> 0) & 0xff;
5126 state = (status >> 8) & 0xff;
5127
5128 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5129 return;
5130 }
5131
5132 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5133 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5134 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005135 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5136 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005137 } else {
5138 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5139 ioc->name, volume);
5140 }
5141
5142 switch(reason) {
5143 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5144 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5145 ioc->name);
5146 break;
5147
5148 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5149
5150 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5151 ioc->name);
5152 break;
5153
5154 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5155 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5156 ioc->name);
5157 break;
5158
5159 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5160 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5161 ioc->name,
5162 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5163 ? "optimal"
5164 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5165 ? "degraded"
5166 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5167 ? "failed"
5168 : "state unknown",
5169 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5170 ? ", enabled" : "",
5171 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5172 ? ", quiesced" : "",
5173 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5174 ? ", resync in progress" : "" );
5175 break;
5176
5177 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5178 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5179 ioc->name, disk);
5180 break;
5181
5182 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5183 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5184 ioc->name);
5185 break;
5186
5187 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5188 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5189 ioc->name);
5190 break;
5191
5192 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5193 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5194 ioc->name);
5195 break;
5196
5197 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5198 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5199 ioc->name,
5200 state == MPI_PHYSDISK0_STATUS_ONLINE
5201 ? "online"
5202 : state == MPI_PHYSDISK0_STATUS_MISSING
5203 ? "missing"
5204 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5205 ? "not compatible"
5206 : state == MPI_PHYSDISK0_STATUS_FAILED
5207 ? "failed"
5208 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5209 ? "initializing"
5210 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5211 ? "offline requested"
5212 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5213 ? "failed requested"
5214 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5215 ? "offline"
5216 : "state unknown",
5217 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5218 ? ", out of sync" : "",
5219 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5220 ? ", quiesced" : "" );
5221 break;
5222
5223 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5224 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5225 ioc->name, disk);
5226 break;
5227
5228 case MPI_EVENT_RAID_RC_SMART_DATA:
5229 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5230 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5231 break;
5232
5233 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5234 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5235 ioc->name, disk);
5236 break;
5237 }
5238}
5239
5240/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005241/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5243 * @ioc: Pointer to MPT_ADAPTER structure
5244 *
5245 * Returns: 0 for success
5246 * -ENOMEM if no memory available
5247 * -EPERM if not allowed due to ISR context
5248 * -EAGAIN if no msg frames currently available
5249 * -EFAULT for non-successful reply or no reply (timeout)
5250 */
5251static int
5252GetIoUnitPage2(MPT_ADAPTER *ioc)
5253{
5254 ConfigPageHeader_t hdr;
5255 CONFIGPARMS cfg;
5256 IOUnitPage2_t *ppage_alloc;
5257 dma_addr_t page_dma;
5258 int data_sz;
5259 int rc;
5260
5261 /* Get the page header */
5262 hdr.PageVersion = 0;
5263 hdr.PageLength = 0;
5264 hdr.PageNumber = 2;
5265 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005266 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267 cfg.physAddr = -1;
5268 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5269 cfg.dir = 0;
5270 cfg.pageAddr = 0;
5271 cfg.timeout = 0;
5272
5273 if ((rc = mpt_config(ioc, &cfg)) != 0)
5274 return rc;
5275
5276 if (hdr.PageLength == 0)
5277 return 0;
5278
5279 /* Read the config page */
5280 data_sz = hdr.PageLength * 4;
5281 rc = -ENOMEM;
5282 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5283 if (ppage_alloc) {
5284 memset((u8 *)ppage_alloc, 0, data_sz);
5285 cfg.physAddr = page_dma;
5286 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5287
5288 /* If Good, save data */
5289 if ((rc = mpt_config(ioc, &cfg)) == 0)
5290 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5291
5292 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5293 }
5294
5295 return rc;
5296}
5297
5298/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005299/**
5300 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005301 * @ioc: Pointer to a Adapter Strucutre
5302 * @portnum: IOC port number
5303 *
5304 * Return: -EFAULT if read of config page header fails
5305 * or if no nvram
5306 * If read of SCSI Port Page 0 fails,
5307 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5308 * Adapter settings: async, narrow
5309 * Return 1
5310 * If read of SCSI Port Page 2 fails,
5311 * Adapter settings valid
5312 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5313 * Return 1
5314 * Else
5315 * Both valid
5316 * Return 0
5317 * CHECK - what type of locking mechanisms should be used????
5318 */
5319static int
5320mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5321{
5322 u8 *pbuf;
5323 dma_addr_t buf_dma;
5324 CONFIGPARMS cfg;
5325 ConfigPageHeader_t header;
5326 int ii;
5327 int data, rc = 0;
5328
5329 /* Allocate memory
5330 */
5331 if (!ioc->spi_data.nvram) {
5332 int sz;
5333 u8 *mem;
5334 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5335 mem = kmalloc(sz, GFP_ATOMIC);
5336 if (mem == NULL)
5337 return -EFAULT;
5338
5339 ioc->spi_data.nvram = (int *) mem;
5340
Prakash, Sathya436ace72007-07-24 15:42:08 +05305341 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342 ioc->name, ioc->spi_data.nvram, sz));
5343 }
5344
5345 /* Invalidate NVRAM information
5346 */
5347 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5348 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5349 }
5350
5351 /* Read SPP0 header, allocate memory, then read page.
5352 */
5353 header.PageVersion = 0;
5354 header.PageLength = 0;
5355 header.PageNumber = 0;
5356 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005357 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358 cfg.physAddr = -1;
5359 cfg.pageAddr = portnum;
5360 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5361 cfg.dir = 0;
5362 cfg.timeout = 0; /* use default */
5363 if (mpt_config(ioc, &cfg) != 0)
5364 return -EFAULT;
5365
5366 if (header.PageLength > 0) {
5367 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5368 if (pbuf) {
5369 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5370 cfg.physAddr = buf_dma;
5371 if (mpt_config(ioc, &cfg) != 0) {
5372 ioc->spi_data.maxBusWidth = MPT_NARROW;
5373 ioc->spi_data.maxSyncOffset = 0;
5374 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5375 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5376 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305377 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5378 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005379 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 } else {
5381 /* Save the Port Page 0 data
5382 */
5383 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5384 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5385 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5386
5387 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5388 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005389 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5390 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 ioc->name, pPP0->Capabilities));
5392 }
5393 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5394 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5395 if (data) {
5396 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5397 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5398 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305399 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5400 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005401 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 } else {
5403 ioc->spi_data.maxSyncOffset = 0;
5404 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5405 }
5406
5407 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5408
5409 /* Update the minSyncFactor based on bus type.
5410 */
5411 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5412 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5413
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005414 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305416 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5417 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005418 ioc->name, ioc->spi_data.minSyncFactor));
5419 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420 }
5421 }
5422 if (pbuf) {
5423 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5424 }
5425 }
5426 }
5427
5428 /* SCSI Port Page 2 - Read the header then the page.
5429 */
5430 header.PageVersion = 0;
5431 header.PageLength = 0;
5432 header.PageNumber = 2;
5433 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005434 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435 cfg.physAddr = -1;
5436 cfg.pageAddr = portnum;
5437 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5438 cfg.dir = 0;
5439 if (mpt_config(ioc, &cfg) != 0)
5440 return -EFAULT;
5441
5442 if (header.PageLength > 0) {
5443 /* Allocate memory and read SCSI Port Page 2
5444 */
5445 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5446 if (pbuf) {
5447 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5448 cfg.physAddr = buf_dma;
5449 if (mpt_config(ioc, &cfg) != 0) {
5450 /* Nvram data is left with INVALID mark
5451 */
5452 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005453 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5454
5455 /* This is an ATTO adapter, read Page2 accordingly
5456 */
5457 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5458 ATTODeviceInfo_t *pdevice = NULL;
5459 u16 ATTOFlags;
5460
5461 /* Save the Port Page 2 data
5462 * (reformat into a 32bit quantity)
5463 */
5464 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5465 pdevice = &pPP2->DeviceSettings[ii];
5466 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5467 data = 0;
5468
5469 /* Translate ATTO device flags to LSI format
5470 */
5471 if (ATTOFlags & ATTOFLAG_DISC)
5472 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5473 if (ATTOFlags & ATTOFLAG_ID_ENB)
5474 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5475 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5476 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5477 if (ATTOFlags & ATTOFLAG_TAGGED)
5478 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5479 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5480 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5481
5482 data = (data << 16) | (pdevice->Period << 8) | 10;
5483 ioc->spi_data.nvram[ii] = data;
5484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485 } else {
5486 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5487 MpiDeviceInfo_t *pdevice = NULL;
5488
Moore, Ericd8e925d2006-01-16 18:53:06 -07005489 /*
5490 * Save "Set to Avoid SCSI Bus Resets" flag
5491 */
5492 ioc->spi_data.bus_reset =
5493 (le32_to_cpu(pPP2->PortFlags) &
5494 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5495 0 : 1 ;
5496
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 /* Save the Port Page 2 data
5498 * (reformat into a 32bit quantity)
5499 */
5500 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5501 ioc->spi_data.PortFlags = data;
5502 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5503 pdevice = &pPP2->DeviceSettings[ii];
5504 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5505 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5506 ioc->spi_data.nvram[ii] = data;
5507 }
5508 }
5509
5510 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5511 }
5512 }
5513
5514 /* Update Adapter limits with those from NVRAM
5515 * Comment: Don't need to do this. Target performance
5516 * parameters will never exceed the adapters limits.
5517 */
5518
5519 return rc;
5520}
5521
5522/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005523/**
5524 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525 * @ioc: Pointer to a Adapter Strucutre
5526 * @portnum: IOC port number
5527 *
5528 * Return: -EFAULT if read of config page header fails
5529 * or 0 if success.
5530 */
5531static int
5532mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5533{
5534 CONFIGPARMS cfg;
5535 ConfigPageHeader_t header;
5536
5537 /* Read the SCSI Device Page 1 header
5538 */
5539 header.PageVersion = 0;
5540 header.PageLength = 0;
5541 header.PageNumber = 1;
5542 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005543 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544 cfg.physAddr = -1;
5545 cfg.pageAddr = portnum;
5546 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5547 cfg.dir = 0;
5548 cfg.timeout = 0;
5549 if (mpt_config(ioc, &cfg) != 0)
5550 return -EFAULT;
5551
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005552 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5553 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554
5555 header.PageVersion = 0;
5556 header.PageLength = 0;
5557 header.PageNumber = 0;
5558 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5559 if (mpt_config(ioc, &cfg) != 0)
5560 return -EFAULT;
5561
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005562 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5563 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005564
Prakash, Sathya436ace72007-07-24 15:42:08 +05305565 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5567
Prakash, Sathya436ace72007-07-24 15:42:08 +05305568 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5570 return 0;
5571}
5572
Eric Mooreb506ade2007-01-29 09:45:37 -07005573/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005574 * mpt_inactive_raid_list_free - This clears this link list.
5575 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005576 **/
5577static void
5578mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5579{
5580 struct inactive_raid_component_info *component_info, *pNext;
5581
5582 if (list_empty(&ioc->raid_data.inactive_list))
5583 return;
5584
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005585 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005586 list_for_each_entry_safe(component_info, pNext,
5587 &ioc->raid_data.inactive_list, list) {
5588 list_del(&component_info->list);
5589 kfree(component_info);
5590 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005591 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005592}
5593
5594/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005595 * 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 -07005596 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005597 * @ioc : pointer to per adapter structure
5598 * @channel : volume channel
5599 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005600 **/
5601static void
5602mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5603{
5604 CONFIGPARMS cfg;
5605 ConfigPageHeader_t hdr;
5606 dma_addr_t dma_handle;
5607 pRaidVolumePage0_t buffer = NULL;
5608 int i;
5609 RaidPhysDiskPage0_t phys_disk;
5610 struct inactive_raid_component_info *component_info;
5611 int handle_inactive_volumes;
5612
5613 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5614 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5615 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5616 cfg.pageAddr = (channel << 8) + id;
5617 cfg.cfghdr.hdr = &hdr;
5618 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5619
5620 if (mpt_config(ioc, &cfg) != 0)
5621 goto out;
5622
5623 if (!hdr.PageLength)
5624 goto out;
5625
5626 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5627 &dma_handle);
5628
5629 if (!buffer)
5630 goto out;
5631
5632 cfg.physAddr = dma_handle;
5633 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5634
5635 if (mpt_config(ioc, &cfg) != 0)
5636 goto out;
5637
5638 if (!buffer->NumPhysDisks)
5639 goto out;
5640
5641 handle_inactive_volumes =
5642 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5643 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5644 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5645 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5646
5647 if (!handle_inactive_volumes)
5648 goto out;
5649
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005650 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005651 for (i = 0; i < buffer->NumPhysDisks; i++) {
5652 if(mpt_raid_phys_disk_pg0(ioc,
5653 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5654 continue;
5655
5656 if ((component_info = kmalloc(sizeof (*component_info),
5657 GFP_KERNEL)) == NULL)
5658 continue;
5659
5660 component_info->volumeID = id;
5661 component_info->volumeBus = channel;
5662 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5663 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5664 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5665 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5666
5667 list_add_tail(&component_info->list,
5668 &ioc->raid_data.inactive_list);
5669 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005670 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005671
5672 out:
5673 if (buffer)
5674 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5675 dma_handle);
5676}
5677
5678/**
5679 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5680 * @ioc: Pointer to a Adapter Structure
5681 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5682 * @phys_disk: requested payload data returned
5683 *
5684 * Return:
5685 * 0 on success
5686 * -EFAULT if read of config page header fails or data pointer not NULL
5687 * -ENOMEM if pci_alloc failed
5688 **/
5689int
Kashyap, Desai2f187862009-05-29 16:52:37 +05305690mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
5691 RaidPhysDiskPage0_t *phys_disk)
Eric Mooreb506ade2007-01-29 09:45:37 -07005692{
Kashyap, Desai2f187862009-05-29 16:52:37 +05305693 CONFIGPARMS cfg;
5694 ConfigPageHeader_t hdr;
Eric Mooreb506ade2007-01-29 09:45:37 -07005695 dma_addr_t dma_handle;
5696 pRaidPhysDiskPage0_t buffer = NULL;
5697 int rc;
5698
5699 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5700 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
Kashyap, Desai2f187862009-05-29 16:52:37 +05305701 memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
Eric Mooreb506ade2007-01-29 09:45:37 -07005702
Kashyap, Desai2f187862009-05-29 16:52:37 +05305703 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
Eric Mooreb506ade2007-01-29 09:45:37 -07005704 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5705 cfg.cfghdr.hdr = &hdr;
5706 cfg.physAddr = -1;
5707 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5708
5709 if (mpt_config(ioc, &cfg) != 0) {
5710 rc = -EFAULT;
5711 goto out;
5712 }
5713
5714 if (!hdr.PageLength) {
5715 rc = -EFAULT;
5716 goto out;
5717 }
5718
5719 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5720 &dma_handle);
5721
5722 if (!buffer) {
5723 rc = -ENOMEM;
5724 goto out;
5725 }
5726
5727 cfg.physAddr = dma_handle;
5728 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5729 cfg.pageAddr = phys_disk_num;
5730
5731 if (mpt_config(ioc, &cfg) != 0) {
5732 rc = -EFAULT;
5733 goto out;
5734 }
5735
5736 rc = 0;
5737 memcpy(phys_disk, buffer, sizeof(*buffer));
5738 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5739
5740 out:
5741
5742 if (buffer)
5743 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5744 dma_handle);
5745
5746 return rc;
5747}
5748
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749/**
5750 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5751 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005752 *
5753 * Return:
5754 * 0 on success
5755 * -EFAULT if read of config page header fails or data pointer not NULL
5756 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005757 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758int
5759mpt_findImVolumes(MPT_ADAPTER *ioc)
5760{
5761 IOCPage2_t *pIoc2;
5762 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005763 dma_addr_t ioc2_dma;
5764 CONFIGPARMS cfg;
5765 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766 int rc = 0;
5767 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005768 int i;
5769
5770 if (!ioc->ir_firmware)
5771 return 0;
5772
5773 /* Free the old page
5774 */
5775 kfree(ioc->raid_data.pIocPg2);
5776 ioc->raid_data.pIocPg2 = NULL;
5777 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778
5779 /* Read IOCP2 header then the page.
5780 */
5781 header.PageVersion = 0;
5782 header.PageLength = 0;
5783 header.PageNumber = 2;
5784 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005785 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005786 cfg.physAddr = -1;
5787 cfg.pageAddr = 0;
5788 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5789 cfg.dir = 0;
5790 cfg.timeout = 0;
5791 if (mpt_config(ioc, &cfg) != 0)
5792 return -EFAULT;
5793
5794 if (header.PageLength == 0)
5795 return -EFAULT;
5796
5797 iocpage2sz = header.PageLength * 4;
5798 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5799 if (!pIoc2)
5800 return -ENOMEM;
5801
5802 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5803 cfg.physAddr = ioc2_dma;
5804 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005805 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005806
Eric Mooreb506ade2007-01-29 09:45:37 -07005807 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5808 if (!mem)
5809 goto out;
5810
Linus Torvalds1da177e2005-04-16 15:20:36 -07005811 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005812 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005813
Eric Mooreb506ade2007-01-29 09:45:37 -07005814 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005815
Eric Mooreb506ade2007-01-29 09:45:37 -07005816 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5817 mpt_inactive_raid_volumes(ioc,
5818 pIoc2->RaidVolume[i].VolumeBus,
5819 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005820
Eric Mooreb506ade2007-01-29 09:45:37 -07005821 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5823
5824 return rc;
5825}
5826
Moore, Ericc972c702006-03-14 09:14:06 -07005827static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005828mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5829{
5830 IOCPage3_t *pIoc3;
5831 u8 *mem;
5832 CONFIGPARMS cfg;
5833 ConfigPageHeader_t header;
5834 dma_addr_t ioc3_dma;
5835 int iocpage3sz = 0;
5836
5837 /* Free the old page
5838 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005839 kfree(ioc->raid_data.pIocPg3);
5840 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005841
5842 /* There is at least one physical disk.
5843 * Read and save IOC Page 3
5844 */
5845 header.PageVersion = 0;
5846 header.PageLength = 0;
5847 header.PageNumber = 3;
5848 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005849 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005850 cfg.physAddr = -1;
5851 cfg.pageAddr = 0;
5852 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5853 cfg.dir = 0;
5854 cfg.timeout = 0;
5855 if (mpt_config(ioc, &cfg) != 0)
5856 return 0;
5857
5858 if (header.PageLength == 0)
5859 return 0;
5860
5861 /* Read Header good, alloc memory
5862 */
5863 iocpage3sz = header.PageLength * 4;
5864 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5865 if (!pIoc3)
5866 return 0;
5867
5868 /* Read the Page and save the data
5869 * into malloc'd memory.
5870 */
5871 cfg.physAddr = ioc3_dma;
5872 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5873 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005874 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875 if (mem) {
5876 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005877 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005878 }
5879 }
5880
5881 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5882
5883 return 0;
5884}
5885
5886static void
5887mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5888{
5889 IOCPage4_t *pIoc4;
5890 CONFIGPARMS cfg;
5891 ConfigPageHeader_t header;
5892 dma_addr_t ioc4_dma;
5893 int iocpage4sz;
5894
5895 /* Read and save IOC Page 4
5896 */
5897 header.PageVersion = 0;
5898 header.PageLength = 0;
5899 header.PageNumber = 4;
5900 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005901 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902 cfg.physAddr = -1;
5903 cfg.pageAddr = 0;
5904 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5905 cfg.dir = 0;
5906 cfg.timeout = 0;
5907 if (mpt_config(ioc, &cfg) != 0)
5908 return;
5909
5910 if (header.PageLength == 0)
5911 return;
5912
5913 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5914 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5915 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5916 if (!pIoc4)
5917 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005918 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919 } else {
5920 ioc4_dma = ioc->spi_data.IocPg4_dma;
5921 iocpage4sz = ioc->spi_data.IocPg4Sz;
5922 }
5923
5924 /* Read the Page into dma memory.
5925 */
5926 cfg.physAddr = ioc4_dma;
5927 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5928 if (mpt_config(ioc, &cfg) == 0) {
5929 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5930 ioc->spi_data.IocPg4_dma = ioc4_dma;
5931 ioc->spi_data.IocPg4Sz = iocpage4sz;
5932 } else {
5933 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5934 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005935 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005936 }
5937}
5938
5939static void
5940mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5941{
5942 IOCPage1_t *pIoc1;
5943 CONFIGPARMS cfg;
5944 ConfigPageHeader_t header;
5945 dma_addr_t ioc1_dma;
5946 int iocpage1sz = 0;
5947 u32 tmp;
5948
5949 /* Check the Coalescing Timeout in IOC Page 1
5950 */
5951 header.PageVersion = 0;
5952 header.PageLength = 0;
5953 header.PageNumber = 1;
5954 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005955 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005956 cfg.physAddr = -1;
5957 cfg.pageAddr = 0;
5958 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5959 cfg.dir = 0;
5960 cfg.timeout = 0;
5961 if (mpt_config(ioc, &cfg) != 0)
5962 return;
5963
5964 if (header.PageLength == 0)
5965 return;
5966
5967 /* Read Header good, alloc memory
5968 */
5969 iocpage1sz = header.PageLength * 4;
5970 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5971 if (!pIoc1)
5972 return;
5973
5974 /* Read the Page and check coalescing timeout
5975 */
5976 cfg.physAddr = ioc1_dma;
5977 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5978 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305979
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5981 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5982 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5983
Prakash, Sathya436ace72007-07-24 15:42:08 +05305984 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005985 ioc->name, tmp));
5986
5987 if (tmp > MPT_COALESCING_TIMEOUT) {
5988 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5989
5990 /* Write NVRAM and current
5991 */
5992 cfg.dir = 1;
5993 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5994 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305995 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005996 ioc->name, MPT_COALESCING_TIMEOUT));
5997
5998 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5999 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306000 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6001 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006002 ioc->name, MPT_COALESCING_TIMEOUT));
6003 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306004 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6005 "Reset NVRAM Coalescing Timeout Failed\n",
6006 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006007 }
6008
6009 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306010 dprintk(ioc, printk(MYIOC_s_WARN_FMT
6011 "Reset of Current Coalescing Timeout Failed!\n",
6012 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006013 }
6014 }
6015
6016 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306017 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006018 }
6019 }
6020
6021 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
6022
6023 return;
6024}
6025
Prakash, Sathyaedb90682007-07-17 14:39:14 +05306026static void
6027mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
6028{
6029 CONFIGPARMS cfg;
6030 ConfigPageHeader_t hdr;
6031 dma_addr_t buf_dma;
6032 ManufacturingPage0_t *pbuf = NULL;
6033
6034 memset(&cfg, 0 , sizeof(CONFIGPARMS));
6035 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
6036
6037 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
6038 cfg.cfghdr.hdr = &hdr;
6039 cfg.physAddr = -1;
6040 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6041 cfg.timeout = 10;
6042
6043 if (mpt_config(ioc, &cfg) != 0)
6044 goto out;
6045
6046 if (!cfg.cfghdr.hdr->PageLength)
6047 goto out;
6048
6049 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6050 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
6051 if (!pbuf)
6052 goto out;
6053
6054 cfg.physAddr = buf_dma;
6055
6056 if (mpt_config(ioc, &cfg) != 0)
6057 goto out;
6058
6059 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
6060 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
6061 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
6062
6063 out:
6064
6065 if (pbuf)
6066 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
6067}
6068
Linus Torvalds1da177e2005-04-16 15:20:36 -07006069/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006070/**
6071 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072 * @ioc: Pointer to MPT_ADAPTER structure
6073 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05306074 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07006075 */
6076static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05306077SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006078{
Kashyap, Desaifd761752009-05-29 16:39:06 +05306079 EventNotification_t evn;
6080 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006081
Kashyap, Desaifd761752009-05-29 16:39:06 +05306082 memset(&evn, 0, sizeof(EventNotification_t));
6083 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006084
Kashyap, Desaifd761752009-05-29 16:39:06 +05306085 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
6086 evn.Switch = EvSwitch;
6087 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006088
Kashyap, Desaifd761752009-05-29 16:39:06 +05306089 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6090 "Sending EventNotification (%d) request %p\n",
6091 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006092
Kashyap, Desaifd761752009-05-29 16:39:06 +05306093 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6094 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6095 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006096}
6097
6098/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6099/**
6100 * SendEventAck - Send EventAck request to MPT adapter.
6101 * @ioc: Pointer to MPT_ADAPTER structure
6102 * @evnp: Pointer to original EventNotification request
6103 */
6104static int
6105SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6106{
6107 EventAck_t *pAck;
6108
6109 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306110 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306111 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006112 return -1;
6113 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006114
Prakash, Sathya436ace72007-07-24 15:42:08 +05306115 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006116
6117 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6118 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006119 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006121 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006122 pAck->Event = evnp->Event;
6123 pAck->EventContext = evnp->EventContext;
6124
6125 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6126
6127 return 0;
6128}
6129
6130/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6131/**
6132 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006133 * @ioc: Pointer to an adapter structure
6134 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135 * action, page address, direction, physical address
6136 * and pointer to a configuration page header
6137 * Page header is updated.
6138 *
6139 * Returns 0 for success
6140 * -EPERM if not allowed due to ISR context
6141 * -EAGAIN if no msg frames currently available
6142 * -EFAULT for non-successful reply or no reply (timeout)
6143 */
6144int
6145mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6146{
6147 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306148 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006149 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006150 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306151 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006152 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306153 long timeout;
6154 int ret;
6155 u8 page_type = 0, extend_page;
6156 unsigned long timeleft;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306157 unsigned long flags;
6158 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306159 u8 issue_hard_reset = 0;
6160 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006161
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006162 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006163 * to be in ISR context, because that is fatal!
6164 */
6165 in_isr = in_interrupt();
6166 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306167 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006168 ioc->name));
6169 return -EPERM;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306170 }
6171
6172 /* don't send a config page during diag reset */
6173 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6174 if (ioc->ioc_reset_in_progress) {
6175 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6176 "%s: busy with host reset\n", ioc->name, __func__));
6177 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6178 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006179 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306180 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006181
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306182 /* don't send if no chance of success */
6183 if (!ioc->active ||
6184 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6185 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6186 "%s: ioc not operational, %d, %xh\n",
6187 ioc->name, __func__, ioc->active,
6188 mpt_GetIocState(ioc, 0)));
6189 return -EFAULT;
6190 }
6191
6192 retry_config:
6193 mutex_lock(&ioc->mptbase_cmds.mutex);
6194 /* init the internal cmd struct */
6195 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6196 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6197
Linus Torvalds1da177e2005-04-16 15:20:36 -07006198 /* Get and Populate a free Frame
6199 */
6200 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306201 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6202 "mpt_config: no msg frames!\n", ioc->name));
6203 ret = -EAGAIN;
6204 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006205 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306206
Linus Torvalds1da177e2005-04-16 15:20:36 -07006207 pReq = (Config_t *)mf;
6208 pReq->Action = pCfg->action;
6209 pReq->Reserved = 0;
6210 pReq->ChainOffset = 0;
6211 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006212
6213 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006214 pReq->ExtPageLength = 0;
6215 pReq->ExtPageType = 0;
6216 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006217
Linus Torvalds1da177e2005-04-16 15:20:36 -07006218 for (ii=0; ii < 8; ii++)
6219 pReq->Reserved2[ii] = 0;
6220
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006221 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6222 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6223 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6224 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6225
6226 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6227 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6228 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6229 pReq->ExtPageType = pExtHdr->ExtPageType;
6230 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6231
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306232 /* Page Length must be treated as a reserved field for the
6233 * extended header.
6234 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006235 pReq->Header.PageLength = 0;
6236 }
6237
Linus Torvalds1da177e2005-04-16 15:20:36 -07006238 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6239
6240 /* Add a SGE to the config request.
6241 */
6242 if (pCfg->dir)
6243 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6244 else
6245 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6246
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306247 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6248 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006249 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306250 page_type = pReq->ExtPageType;
6251 extend_page = 1;
6252 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006253 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306254 page_type = pReq->Header.PageType;
6255 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006256 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006257
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306258 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6259 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6260 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6261
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306262 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306263 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306265 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6266 timeout);
6267 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6268 ret = -ETIME;
6269 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6270 "Failed Sending Config request type 0x%x, page 0x%x,"
6271 " action %d, status %xh, time left %ld\n\n",
6272 ioc->name, page_type, pReq->Header.PageNumber,
6273 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6274 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6275 goto out;
6276 if (!timeleft)
6277 issue_hard_reset = 1;
6278 goto out;
6279 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006280
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306281 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6282 ret = -1;
6283 goto out;
6284 }
6285 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6286 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6287 if (ret == MPI_IOCSTATUS_SUCCESS) {
6288 if (extend_page) {
6289 pCfg->cfghdr.ehdr->ExtPageLength =
6290 le16_to_cpu(pReply->ExtPageLength);
6291 pCfg->cfghdr.ehdr->ExtPageType =
6292 pReply->ExtPageType;
6293 }
6294 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6295 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6296 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6297 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006298
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006300
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306301 if (retry_count)
6302 printk(MYIOC_s_INFO_FMT "Retry completed "
6303 "ret=0x%x timeleft=%ld\n",
6304 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006305
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306306 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6307 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006308
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306309out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006310
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306311 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6312 mutex_unlock(&ioc->mptbase_cmds.mutex);
6313 if (issue_hard_reset) {
6314 issue_hard_reset = 0;
6315 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
6316 ioc->name, __func__);
6317 mpt_HardResetHandler(ioc, CAN_SLEEP);
6318 mpt_free_msg_frame(ioc, mf);
6319 /* attempt one retry for a timed out command */
6320 if (!retry_count) {
6321 printk(MYIOC_s_INFO_FMT
6322 "Attempting Retry Config request"
6323 " type 0x%x, page 0x%x,"
6324 " action %d\n", ioc->name, page_type,
6325 pCfg->cfghdr.hdr->PageNumber, pCfg->action);
6326 retry_count++;
6327 goto retry_config;
6328 }
6329 }
6330 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006331
Linus Torvalds1da177e2005-04-16 15:20:36 -07006332}
6333
6334/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006335/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006336 * mpt_ioc_reset - Base cleanup for hard reset
6337 * @ioc: Pointer to the adapter structure
6338 * @reset_phase: Indicates pre- or post-reset functionality
6339 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006340 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006341 */
6342static int
6343mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6344{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306345 switch (reset_phase) {
6346 case MPT_IOC_SETUP_RESET:
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306347 ioc->taskmgmt_quiesce_io = 1;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306348 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6349 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
6350 break;
6351 case MPT_IOC_PRE_RESET:
6352 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6353 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
6354 break;
6355 case MPT_IOC_POST_RESET:
6356 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6357 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
6358/* wake up mptbase_cmds */
6359 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6360 ioc->mptbase_cmds.status |=
6361 MPT_MGMT_STATUS_DID_IOCRESET;
6362 complete(&ioc->mptbase_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006363 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306364/* wake up taskmgmt_cmds */
6365 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
6366 ioc->taskmgmt_cmds.status |=
6367 MPT_MGMT_STATUS_DID_IOCRESET;
6368 complete(&ioc->taskmgmt_cmds.done);
6369 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306370 break;
6371 default:
6372 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006373 }
6374
6375 return 1; /* currently means nothing really */
6376}
6377
6378
6379#ifdef CONFIG_PROC_FS /* { */
6380/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6381/*
6382 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6383 */
6384/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006385/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006386 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6387 *
6388 * Returns 0 for success, non-zero for failure.
6389 */
6390static int
6391procmpt_create(void)
6392{
6393 struct proc_dir_entry *ent;
6394
6395 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6396 if (mpt_proc_root_dir == NULL)
6397 return -ENOTDIR;
6398
6399 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6400 if (ent)
6401 ent->read_proc = procmpt_summary_read;
6402
6403 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6404 if (ent)
6405 ent->read_proc = procmpt_version_read;
6406
6407 return 0;
6408}
6409
6410/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006411/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006412 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6413 *
6414 * Returns 0 for success, non-zero for failure.
6415 */
6416static void
6417procmpt_destroy(void)
6418{
6419 remove_proc_entry("version", mpt_proc_root_dir);
6420 remove_proc_entry("summary", mpt_proc_root_dir);
6421 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6422}
6423
6424/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006425/**
6426 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006427 * @buf: Pointer to area to write information
6428 * @start: Pointer to start pointer
6429 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006430 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006431 * @eof: Pointer to EOF integer
6432 * @data: Pointer
6433 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006434 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006435 * Returns number of characters written to process performing the read.
6436 */
6437static int
6438procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6439{
6440 MPT_ADAPTER *ioc;
6441 char *out = buf;
6442 int len;
6443
6444 if (data) {
6445 int more = 0;
6446
6447 ioc = data;
6448 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6449
6450 out += more;
6451 } else {
6452 list_for_each_entry(ioc, &ioc_list, list) {
6453 int more = 0;
6454
6455 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6456
6457 out += more;
6458 if ((out-buf) >= request)
6459 break;
6460 }
6461 }
6462
6463 len = out - buf;
6464
6465 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6466}
6467
6468/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006469/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006470 * procmpt_version_read - Handle read request from /proc/mpt/version.
6471 * @buf: Pointer to area to write information
6472 * @start: Pointer to start pointer
6473 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006474 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006475 * @eof: Pointer to EOF integer
6476 * @data: Pointer
6477 *
6478 * Returns number of characters written to process performing the read.
6479 */
6480static int
6481procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6482{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306483 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006484 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006485 char *drvname;
6486 int len;
6487
6488 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6489 len += sprintf(buf+len, " Fusion MPT base driver\n");
6490
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006491 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006492 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006493 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306494 if (MptCallbacks[cb_idx]) {
6495 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006496 case MPTSPI_DRIVER:
6497 if (!scsi++) drvname = "SPI host";
6498 break;
6499 case MPTFC_DRIVER:
6500 if (!fc++) drvname = "FC host";
6501 break;
6502 case MPTSAS_DRIVER:
6503 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006504 break;
6505 case MPTLAN_DRIVER:
6506 if (!lan++) drvname = "LAN";
6507 break;
6508 case MPTSTM_DRIVER:
6509 if (!targ++) drvname = "SCSI target";
6510 break;
6511 case MPTCTL_DRIVER:
6512 if (!ctl++) drvname = "ioctl";
6513 break;
6514 }
6515
6516 if (drvname)
6517 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6518 }
6519 }
6520
6521 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6522}
6523
6524/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006525/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006526 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6527 * @buf: Pointer to area to write information
6528 * @start: Pointer to start pointer
6529 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006530 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006531 * @eof: Pointer to EOF integer
6532 * @data: Pointer
6533 *
6534 * Returns number of characters written to process performing the read.
6535 */
6536static int
6537procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6538{
6539 MPT_ADAPTER *ioc = data;
6540 int len;
6541 char expVer[32];
6542 int sz;
6543 int p;
6544
6545 mpt_get_fw_exp_ver(expVer, ioc);
6546
6547 len = sprintf(buf, "%s:", ioc->name);
6548 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6549 len += sprintf(buf+len, " (f/w download boot flag set)");
6550// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6551// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6552
6553 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6554 ioc->facts.ProductID,
6555 ioc->prod_name);
6556 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6557 if (ioc->facts.FWImageSize)
6558 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6559 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6560 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6561 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6562
6563 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6564 ioc->facts.CurrentHostMfaHighAddr);
6565 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6566 ioc->facts.CurrentSenseBufferHighAddr);
6567
6568 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6569 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6570
6571 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6572 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6573 /*
6574 * Rounding UP to nearest 4-kB boundary here...
6575 */
6576 sz = (ioc->req_sz * ioc->req_depth) + 128;
6577 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6578 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6579 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6580 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6581 4*ioc->facts.RequestFrameSize,
6582 ioc->facts.GlobalCredits);
6583
6584 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6585 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6586 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6587 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6588 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6589 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6590 ioc->facts.CurReplyFrameSize,
6591 ioc->facts.ReplyQueueDepth);
6592
6593 len += sprintf(buf+len, " MaxDevices = %d\n",
6594 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6595 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6596
6597 /* per-port info */
6598 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6599 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6600 p+1,
6601 ioc->facts.NumberOfPorts);
6602 if (ioc->bus_type == FC) {
6603 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6604 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6605 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6606 a[5], a[4], a[3], a[2], a[1], a[0]);
6607 }
6608 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6609 ioc->fc_port_page0[p].WWNN.High,
6610 ioc->fc_port_page0[p].WWNN.Low,
6611 ioc->fc_port_page0[p].WWPN.High,
6612 ioc->fc_port_page0[p].WWPN.Low);
6613 }
6614 }
6615
6616 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6617}
6618
6619#endif /* CONFIG_PROC_FS } */
6620
6621/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6622static void
6623mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6624{
6625 buf[0] ='\0';
6626 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6627 sprintf(buf, " (Exp %02d%02d)",
6628 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6629 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6630
6631 /* insider hack! */
6632 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6633 strcat(buf, " [MDBG]");
6634 }
6635}
6636
6637/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6638/**
6639 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6640 * @ioc: Pointer to MPT_ADAPTER structure
6641 * @buffer: Pointer to buffer where IOC summary info should be written
6642 * @size: Pointer to number of bytes we wrote (set by this routine)
6643 * @len: Offset at which to start writing in buffer
6644 * @showlan: Display LAN stuff?
6645 *
6646 * This routine writes (english readable) ASCII text, which represents
6647 * a summary of IOC information, to a buffer.
6648 */
6649void
6650mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6651{
6652 char expVer[32];
6653 int y;
6654
6655 mpt_get_fw_exp_ver(expVer, ioc);
6656
6657 /*
6658 * Shorter summary of attached ioc's...
6659 */
6660 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6661 ioc->name,
6662 ioc->prod_name,
6663 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6664 ioc->facts.FWVersion.Word,
6665 expVer,
6666 ioc->facts.NumberOfPorts,
6667 ioc->req_depth);
6668
6669 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6670 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6671 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6672 a[5], a[4], a[3], a[2], a[1], a[0]);
6673 }
6674
Linus Torvalds1da177e2005-04-16 15:20:36 -07006675 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006676
6677 if (!ioc->active)
6678 y += sprintf(buffer+len+y, " (disabled)");
6679
6680 y += sprintf(buffer+len+y, "\n");
6681
6682 *size = y;
6683}
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306684/**
6685 * mpt_set_taskmgmt_in_progress_flag - set flags associated with task managment
6686 * @ioc: Pointer to MPT_ADAPTER structure
6687 *
6688 * Returns 0 for SUCCESS or -1 if FAILED.
6689 *
6690 * If -1 is return, then it was not possible to set the flags
6691 **/
6692int
6693mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6694{
6695 unsigned long flags;
6696 int retval;
6697
6698 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6699 if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
6700 (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
6701 retval = -1;
6702 goto out;
6703 }
6704 retval = 0;
6705 ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306706 ioc->taskmgmt_quiesce_io = 1;
6707 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306708 ioc->alt_ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306709 ioc->alt_ioc->taskmgmt_quiesce_io = 1;
6710 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306711 out:
6712 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6713 return retval;
6714}
6715EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
6716
6717/**
6718 * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task managment
6719 * @ioc: Pointer to MPT_ADAPTER structure
6720 *
6721 **/
6722void
6723mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6724{
6725 unsigned long flags;
6726
6727 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6728 ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306729 ioc->taskmgmt_quiesce_io = 0;
6730 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306731 ioc->alt_ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306732 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
6733 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306734 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6735}
6736EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006737
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306738
6739/**
6740 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6741 * the kernel
6742 * @ioc: Pointer to MPT_ADAPTER structure
6743 *
6744 **/
6745void
6746mpt_halt_firmware(MPT_ADAPTER *ioc)
6747{
6748 u32 ioc_raw_state;
6749
6750 ioc_raw_state = mpt_GetIocState(ioc, 0);
6751
6752 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6753 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6754 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6755 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6756 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6757 } else {
6758 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6759 panic("%s: Firmware is halted due to command timeout\n",
6760 ioc->name);
6761 }
6762}
6763EXPORT_SYMBOL(mpt_halt_firmware);
6764
Linus Torvalds1da177e2005-04-16 15:20:36 -07006765/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6766/*
6767 * Reset Handling
6768 */
6769/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6770/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006771 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006772 * @ioc: Pointer to MPT_ADAPTER structure
6773 * @sleepFlag: Indicates if sleep or schedule must be called.
6774 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006775 * Issues SCSI Task Management call based on input arg values.
6776 * If TaskMgmt fails, returns associated SCSI request.
6777 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006778 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6779 * or a non-interrupt thread. In the former, must not call schedule().
6780 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006781 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006782 * FW reload/initialization failed.
6783 *
6784 * Returns 0 for SUCCESS or -1 if FAILED.
6785 */
6786int
6787mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6788{
6789 int rc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306790 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006791 unsigned long flags;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306792 unsigned long time_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006793
Prakash, Sathya436ace72007-07-24 15:42:08 +05306794 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006795#ifdef MFCNT
6796 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6797 printk("MF count 0x%x !\n", ioc->mfcnt);
6798#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306799 if (mpt_fwfault_debug)
6800 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006801
6802 /* Reset the adapter. Prevent more than 1 call to
6803 * mpt_do_ioc_recovery at any instant in time.
6804 */
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306805 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6806 if (ioc->ioc_reset_in_progress) {
6807 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006808 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006809 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306810 ioc->ioc_reset_in_progress = 1;
6811 if (ioc->alt_ioc)
6812 ioc->alt_ioc->ioc_reset_in_progress = 1;
6813 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006814
6815 /* FIXME: If do_ioc_recovery fails, repeat....
6816 */
6817
6818 /* The SCSI driver needs to adjust timeouts on all current
6819 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006820 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006821 * For all other protocol drivers, this is a no-op.
6822 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05306823 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6824 if (MptResetHandlers[cb_idx]) {
6825 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
6826 if (ioc->alt_ioc)
6827 mpt_signal_reset(cb_idx, ioc->alt_ioc,
6828 MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006829 }
6830 }
6831
Kashyap, Desai2f187862009-05-29 16:52:37 +05306832 time_count = jiffies;
6833 rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
6834 if (rc != 0) {
6835 printk(KERN_WARNING MYNAM
6836 ": WARNING - (%d) Cannot recover %s\n", rc, ioc->name);
6837 } else {
6838 if (ioc->hard_resets < -1)
6839 ioc->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006840 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006841
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306842 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6843 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306844 ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306845 ioc->taskmgmt_in_progress = 0;
6846 if (ioc->alt_ioc) {
6847 ioc->alt_ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306848 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306849 ioc->alt_ioc->taskmgmt_in_progress = 0;
6850 }
6851 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006852
Kashyap, Desai2f187862009-05-29 16:52:37 +05306853 dtmprintk(ioc,
6854 printk(MYIOC_s_DEBUG_FMT
6855 "HardResetHandler: completed (%d seconds): %s\n", ioc->name,
6856 jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?
6857 "SUCCESS" : "FAILED")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006858
6859 return rc;
6860}
6861
Kashyap, Desai2f187862009-05-29 16:52:37 +05306862#ifdef CONFIG_FUSION_LOGGING
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006863static void
Kashyap, Desai2f187862009-05-29 16:52:37 +05306864mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006865{
Eric Moore509e5e52006-04-26 13:22:37 -06006866 char *ds = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306867 u32 evData0;
6868 int ii;
6869 u8 event;
6870 char *evStr = ioc->evStr;
6871
6872 event = le32_to_cpu(pEventReply->Event) & 0xFF;
6873 evData0 = le32_to_cpu(pEventReply->Data[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006874
6875 switch(event) {
6876 case MPI_EVENT_NONE:
6877 ds = "None";
6878 break;
6879 case MPI_EVENT_LOG_DATA:
6880 ds = "Log Data";
6881 break;
6882 case MPI_EVENT_STATE_CHANGE:
6883 ds = "State Change";
6884 break;
6885 case MPI_EVENT_UNIT_ATTENTION:
6886 ds = "Unit Attention";
6887 break;
6888 case MPI_EVENT_IOC_BUS_RESET:
6889 ds = "IOC Bus Reset";
6890 break;
6891 case MPI_EVENT_EXT_BUS_RESET:
6892 ds = "External Bus Reset";
6893 break;
6894 case MPI_EVENT_RESCAN:
6895 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006896 break;
6897 case MPI_EVENT_LINK_STATUS_CHANGE:
6898 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6899 ds = "Link Status(FAILURE) Change";
6900 else
6901 ds = "Link Status(ACTIVE) Change";
6902 break;
6903 case MPI_EVENT_LOOP_STATE_CHANGE:
6904 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6905 ds = "Loop State(LIP) Change";
6906 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Kashyap, Desai2f187862009-05-29 16:52:37 +05306907 ds = "Loop State(LPE) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006908 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05306909 ds = "Loop State(LPB) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006910 break;
6911 case MPI_EVENT_LOGOUT:
6912 ds = "Logout";
6913 break;
6914 case MPI_EVENT_EVENT_CHANGE:
6915 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006916 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006917 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006918 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006919 break;
6920 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006921 {
6922 u8 ReasonCode = (u8)(evData0 >> 16);
6923 switch (ReasonCode) {
6924 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6925 ds = "Integrated Raid: Volume Created";
6926 break;
6927 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6928 ds = "Integrated Raid: Volume Deleted";
6929 break;
6930 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6931 ds = "Integrated Raid: Volume Settings Changed";
6932 break;
6933 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6934 ds = "Integrated Raid: Volume Status Changed";
6935 break;
6936 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6937 ds = "Integrated Raid: Volume Physdisk Changed";
6938 break;
6939 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6940 ds = "Integrated Raid: Physdisk Created";
6941 break;
6942 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6943 ds = "Integrated Raid: Physdisk Deleted";
6944 break;
6945 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6946 ds = "Integrated Raid: Physdisk Settings Changed";
6947 break;
6948 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6949 ds = "Integrated Raid: Physdisk Status Changed";
6950 break;
6951 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6952 ds = "Integrated Raid: Domain Validation Needed";
6953 break;
6954 case MPI_EVENT_RAID_RC_SMART_DATA :
6955 ds = "Integrated Raid; Smart Data";
6956 break;
6957 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6958 ds = "Integrated Raid: Replace Action Started";
6959 break;
6960 default:
6961 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006962 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006963 }
6964 break;
6965 }
6966 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6967 ds = "SCSI Device Status Change";
6968 break;
6969 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6970 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006971 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006972 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006973 u8 ReasonCode = (u8)(evData0 >> 16);
6974 switch (ReasonCode) {
6975 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006976 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006977 "SAS Device Status Change: Added: "
6978 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006979 break;
6980 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006981 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006982 "SAS Device Status Change: Deleted: "
6983 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006984 break;
6985 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006986 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006987 "SAS Device Status Change: SMART Data: "
6988 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006989 break;
6990 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006991 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006992 "SAS Device Status Change: No Persistancy: "
6993 "id=%d channel=%d", id, channel);
6994 break;
6995 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6996 snprintf(evStr, EVENT_DESCR_STR_SZ,
6997 "SAS Device Status Change: Unsupported Device "
6998 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006999 break;
7000 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
7001 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007002 "SAS Device Status Change: Internal Device "
7003 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007004 break;
7005 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
7006 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007007 "SAS Device Status Change: Internal Task "
7008 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007009 break;
7010 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
7011 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007012 "SAS Device Status Change: Internal Abort "
7013 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007014 break;
7015 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
7016 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007017 "SAS Device Status Change: Internal Clear "
7018 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007019 break;
7020 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
7021 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007022 "SAS Device Status Change: Internal Query "
7023 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007024 break;
7025 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007026 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007027 "SAS Device Status Change: Unknown: "
7028 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06007029 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007030 }
7031 break;
7032 }
7033 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
7034 ds = "Bus Timer Expired";
7035 break;
7036 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07007037 {
7038 u16 curr_depth = (u16)(evData0 >> 16);
7039 u8 channel = (u8)(evData0 >> 8);
7040 u8 id = (u8)(evData0);
7041
7042 snprintf(evStr, EVENT_DESCR_STR_SZ,
7043 "Queue Full: channel=%d id=%d depth=%d",
7044 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007045 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07007046 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007047 case MPI_EVENT_SAS_SES:
7048 ds = "SAS SES Event";
7049 break;
7050 case MPI_EVENT_PERSISTENT_TABLE_FULL:
7051 ds = "Persistent Table Full";
7052 break;
7053 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07007054 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007055 u8 LinkRates = (u8)(evData0 >> 8);
7056 u8 PhyNumber = (u8)(evData0);
7057 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
7058 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
7059 switch (LinkRates) {
7060 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06007061 snprintf(evStr, EVENT_DESCR_STR_SZ,
7062 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007063 " Rate Unknown",PhyNumber);
7064 break;
7065 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06007066 snprintf(evStr, EVENT_DESCR_STR_SZ,
7067 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007068 " Phy Disabled",PhyNumber);
7069 break;
7070 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06007071 snprintf(evStr, EVENT_DESCR_STR_SZ,
7072 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007073 " Failed Speed Nego",PhyNumber);
7074 break;
7075 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06007076 snprintf(evStr, EVENT_DESCR_STR_SZ,
7077 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007078 " Sata OOB Completed",PhyNumber);
7079 break;
7080 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06007081 snprintf(evStr, EVENT_DESCR_STR_SZ,
7082 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007083 " Rate 1.5 Gbps",PhyNumber);
7084 break;
7085 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06007086 snprintf(evStr, EVENT_DESCR_STR_SZ,
7087 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007088 " Rate 3.0 Gpbs",PhyNumber);
7089 break;
7090 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007091 snprintf(evStr, EVENT_DESCR_STR_SZ,
7092 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007093 break;
7094 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007095 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007096 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007097 case MPI_EVENT_SAS_DISCOVERY_ERROR:
7098 ds = "SAS Discovery Error";
7099 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007100 case MPI_EVENT_IR_RESYNC_UPDATE:
7101 {
7102 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06007103 snprintf(evStr, EVENT_DESCR_STR_SZ,
7104 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07007105 break;
7106 }
7107 case MPI_EVENT_IR2:
7108 {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307109 u8 id = (u8)(evData0);
7110 u8 channel = (u8)(evData0 >> 8);
7111 u8 phys_num = (u8)(evData0 >> 24);
Moore, Eric3a892be2006-03-14 09:14:03 -07007112 u8 ReasonCode = (u8)(evData0 >> 16);
Kashyap, Desai2f187862009-05-29 16:52:37 +05307113
Moore, Eric3a892be2006-03-14 09:14:03 -07007114 switch (ReasonCode) {
7115 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307116 snprintf(evStr, EVENT_DESCR_STR_SZ,
7117 "IR2: LD State Changed: "
7118 "id=%d channel=%d phys_num=%d",
7119 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007120 break;
7121 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307122 snprintf(evStr, EVENT_DESCR_STR_SZ,
7123 "IR2: PD State Changed "
7124 "id=%d channel=%d phys_num=%d",
7125 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007126 break;
7127 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307128 snprintf(evStr, EVENT_DESCR_STR_SZ,
7129 "IR2: Bad Block Table Full: "
7130 "id=%d channel=%d phys_num=%d",
7131 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007132 break;
7133 case MPI_EVENT_IR2_RC_PD_INSERTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307134 snprintf(evStr, EVENT_DESCR_STR_SZ,
7135 "IR2: PD Inserted: "
7136 "id=%d channel=%d phys_num=%d",
7137 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007138 break;
7139 case MPI_EVENT_IR2_RC_PD_REMOVED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307140 snprintf(evStr, EVENT_DESCR_STR_SZ,
7141 "IR2: PD Removed: "
7142 "id=%d channel=%d phys_num=%d",
7143 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007144 break;
7145 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307146 snprintf(evStr, EVENT_DESCR_STR_SZ,
7147 "IR2: Foreign CFG Detected: "
7148 "id=%d channel=%d phys_num=%d",
7149 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007150 break;
7151 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307152 snprintf(evStr, EVENT_DESCR_STR_SZ,
7153 "IR2: Rebuild Medium Error: "
7154 "id=%d channel=%d phys_num=%d",
7155 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007156 break;
7157 default:
7158 ds = "IR2";
7159 break;
7160 }
7161 break;
7162 }
7163 case MPI_EVENT_SAS_DISCOVERY:
7164 {
7165 if (evData0)
7166 ds = "SAS Discovery: Start";
7167 else
7168 ds = "SAS Discovery: Stop";
7169 break;
7170 }
7171 case MPI_EVENT_LOG_ENTRY_ADDED:
7172 ds = "SAS Log Entry Added";
7173 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007174
Eric Moorec6c727a2007-01-29 09:44:54 -07007175 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
7176 {
7177 u8 phy_num = (u8)(evData0);
7178 u8 port_num = (u8)(evData0 >> 8);
7179 u8 port_width = (u8)(evData0 >> 16);
7180 u8 primative = (u8)(evData0 >> 24);
7181 snprintf(evStr, EVENT_DESCR_STR_SZ,
7182 "SAS Broadcase Primative: phy=%d port=%d "
7183 "width=%d primative=0x%02x",
7184 phy_num, port_num, port_width, primative);
7185 break;
7186 }
7187
7188 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7189 {
7190 u8 reason = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007191
Kashyap, Desai2f187862009-05-29 16:52:37 +05307192 switch (reason) {
7193 case MPI_EVENT_SAS_INIT_RC_ADDED:
7194 ds = "SAS Initiator Status Change: Added";
7195 break;
7196 case MPI_EVENT_SAS_INIT_RC_REMOVED:
7197 ds = "SAS Initiator Status Change: Deleted";
7198 break;
7199 default:
7200 ds = "SAS Initiator Status Change";
7201 break;
7202 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007203 break;
7204 }
7205
7206 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7207 {
7208 u8 max_init = (u8)(evData0);
7209 u8 current_init = (u8)(evData0 >> 8);
7210
7211 snprintf(evStr, EVENT_DESCR_STR_SZ,
7212 "SAS Initiator Device Table Overflow: max initiators=%02d "
7213 "current initators=%02d",
7214 max_init, current_init);
7215 break;
7216 }
7217 case MPI_EVENT_SAS_SMP_ERROR:
7218 {
7219 u8 status = (u8)(evData0);
7220 u8 port_num = (u8)(evData0 >> 8);
7221 u8 result = (u8)(evData0 >> 16);
7222
7223 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7224 snprintf(evStr, EVENT_DESCR_STR_SZ,
7225 "SAS SMP Error: port=%d result=0x%02x",
7226 port_num, result);
7227 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7228 snprintf(evStr, EVENT_DESCR_STR_SZ,
7229 "SAS SMP Error: port=%d : CRC Error",
7230 port_num);
7231 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7232 snprintf(evStr, EVENT_DESCR_STR_SZ,
7233 "SAS SMP Error: port=%d : Timeout",
7234 port_num);
7235 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7236 snprintf(evStr, EVENT_DESCR_STR_SZ,
7237 "SAS SMP Error: port=%d : No Destination",
7238 port_num);
7239 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7240 snprintf(evStr, EVENT_DESCR_STR_SZ,
7241 "SAS SMP Error: port=%d : Bad Destination",
7242 port_num);
7243 else
7244 snprintf(evStr, EVENT_DESCR_STR_SZ,
7245 "SAS SMP Error: port=%d : status=0x%02x",
7246 port_num, status);
7247 break;
7248 }
7249
Kashyap, Desai2f187862009-05-29 16:52:37 +05307250 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
7251 {
7252 u8 reason = (u8)(evData0);
7253
7254 switch (reason) {
7255 case MPI_EVENT_SAS_EXP_RC_ADDED:
7256 ds = "Expander Status Change: Added";
7257 break;
7258 case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
7259 ds = "Expander Status Change: Deleted";
7260 break;
7261 default:
7262 ds = "Expander Status Change";
7263 break;
7264 }
7265 break;
7266 }
7267
Linus Torvalds1da177e2005-04-16 15:20:36 -07007268 /*
7269 * MPT base "custom" events may be added here...
7270 */
7271 default:
7272 ds = "Unknown";
7273 break;
7274 }
Eric Moore509e5e52006-04-26 13:22:37 -06007275 if (ds)
7276 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007277
Kashyap, Desai2f187862009-05-29 16:52:37 +05307278
7279 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7280 "MPT event:(%02Xh) : %s\n",
7281 ioc->name, event, evStr));
7282
7283 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
7284 ": Event data:\n"));
7285 for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
7286 devtverboseprintk(ioc, printk(" %08x",
7287 le32_to_cpu(pEventReply->Data[ii])));
7288 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
7289}
7290#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007291/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007292/**
7293 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007294 * @ioc: Pointer to MPT_ADAPTER structure
7295 * @pEventReply: Pointer to EventNotification reply frame
7296 * @evHandlers: Pointer to integer, number of event handlers
7297 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007298 * Routes a received EventNotificationReply to all currently registered
7299 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007300 * Returns sum of event handlers return values.
7301 */
7302static int
7303ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7304{
7305 u16 evDataLen;
7306 u32 evData0 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007307 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307308 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007309 int r = 0;
7310 int handlers = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007311 u8 event;
7312
7313 /*
7314 * Do platform normalization of values
7315 */
7316 event = le32_to_cpu(pEventReply->Event) & 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007317 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7318 if (evDataLen) {
7319 evData0 = le32_to_cpu(pEventReply->Data[0]);
7320 }
7321
Prakash, Sathya436ace72007-07-24 15:42:08 +05307322#ifdef CONFIG_FUSION_LOGGING
Kashyap, Desai2f187862009-05-29 16:52:37 +05307323 if (evDataLen)
7324 mpt_display_event_info(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007325#endif
7326
7327 /*
7328 * Do general / base driver event processing
7329 */
7330 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007331 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7332 if (evDataLen) {
7333 u8 evState = evData0 & 0xFF;
7334
7335 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7336
7337 /* Update EventState field in cached IocFacts */
7338 if (ioc->facts.Function) {
7339 ioc->facts.EventState = evState;
7340 }
7341 }
7342 break;
Moore, Ericece50912006-01-16 18:53:19 -07007343 case MPI_EVENT_INTEGRATED_RAID:
7344 mptbase_raid_process_event_data(ioc,
7345 (MpiEventDataRaid_t *)pEventReply->Data);
7346 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007347 default:
7348 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007349 }
7350
7351 /*
7352 * Should this event be logged? Events are written sequentially.
7353 * When buffer is full, start again at the top.
7354 */
7355 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7356 int idx;
7357
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007358 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007359
7360 ioc->events[idx].event = event;
7361 ioc->events[idx].eventContext = ioc->eventContext;
7362
7363 for (ii = 0; ii < 2; ii++) {
7364 if (ii < evDataLen)
7365 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7366 else
7367 ioc->events[idx].data[ii] = 0;
7368 }
7369
7370 ioc->eventContext++;
7371 }
7372
7373
7374 /*
7375 * Call each currently registered protocol event handler.
7376 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007377 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307378 if (MptEvHandlers[cb_idx]) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307379 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7380 "Routing Event to event handler #%d\n",
7381 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307382 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007383 handlers++;
7384 }
7385 }
7386 /* FIXME? Examine results here? */
7387
7388 /*
7389 * If needed, send (a single) EventAck.
7390 */
7391 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307392 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007393 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007394 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307395 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007396 ioc->name, ii));
7397 }
7398 }
7399
7400 *evHandlers = handlers;
7401 return r;
7402}
7403
7404/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007405/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007406 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7407 * @ioc: Pointer to MPT_ADAPTER structure
7408 * @log_info: U32 LogInfo reply word from the IOC
7409 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007410 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007411 */
7412static void
7413mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7414{
Eric Moore7c431e52007-06-13 16:34:36 -06007415 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007416
Eric Moore7c431e52007-06-13 16:34:36 -06007417 switch (log_info & 0xFF000000) {
7418 case MPI_IOCLOGINFO_FC_INIT_BASE:
7419 desc = "FCP Initiator";
7420 break;
7421 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7422 desc = "FCP Target";
7423 break;
7424 case MPI_IOCLOGINFO_FC_LAN_BASE:
7425 desc = "LAN";
7426 break;
7427 case MPI_IOCLOGINFO_FC_MSG_BASE:
7428 desc = "MPI Message Layer";
7429 break;
7430 case MPI_IOCLOGINFO_FC_LINK_BASE:
7431 desc = "FC Link";
7432 break;
7433 case MPI_IOCLOGINFO_FC_CTX_BASE:
7434 desc = "Context Manager";
7435 break;
7436 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7437 desc = "Invalid Field Offset";
7438 break;
7439 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7440 desc = "State Change Info";
7441 break;
7442 }
7443
7444 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7445 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007446}
7447
7448/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007449/**
Moore, Eric335a9412006-01-17 17:06:23 -07007450 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007451 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007452 * @log_info: U32 LogInfo word from the IOC
7453 *
7454 * Refer to lsi/sp_log.h.
7455 */
7456static void
Moore, Eric335a9412006-01-17 17:06:23 -07007457mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007458{
7459 u32 info = log_info & 0x00FF0000;
7460 char *desc = "unknown";
7461
7462 switch (info) {
7463 case 0x00010000:
7464 desc = "bug! MID not found";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007465 break;
7466
7467 case 0x00020000:
7468 desc = "Parity Error";
7469 break;
7470
7471 case 0x00030000:
7472 desc = "ASYNC Outbound Overrun";
7473 break;
7474
7475 case 0x00040000:
7476 desc = "SYNC Offset Error";
7477 break;
7478
7479 case 0x00050000:
7480 desc = "BM Change";
7481 break;
7482
7483 case 0x00060000:
7484 desc = "Msg In Overflow";
7485 break;
7486
7487 case 0x00070000:
7488 desc = "DMA Error";
7489 break;
7490
7491 case 0x00080000:
7492 desc = "Outbound DMA Overrun";
7493 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007494
Linus Torvalds1da177e2005-04-16 15:20:36 -07007495 case 0x00090000:
7496 desc = "Task Management";
7497 break;
7498
7499 case 0x000A0000:
7500 desc = "Device Problem";
7501 break;
7502
7503 case 0x000B0000:
7504 desc = "Invalid Phase Change";
7505 break;
7506
7507 case 0x000C0000:
7508 desc = "Untagged Table Size";
7509 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007510
Linus Torvalds1da177e2005-04-16 15:20:36 -07007511 }
7512
7513 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7514}
7515
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007516/* strings for sas loginfo */
7517 static char *originator_str[] = {
7518 "IOP", /* 00h */
7519 "PL", /* 01h */
7520 "IR" /* 02h */
7521 };
7522 static char *iop_code_str[] = {
7523 NULL, /* 00h */
7524 "Invalid SAS Address", /* 01h */
7525 NULL, /* 02h */
7526 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007527 "Diag Message Error", /* 04h */
7528 "Task Terminated", /* 05h */
7529 "Enclosure Management", /* 06h */
7530 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007531 };
7532 static char *pl_code_str[] = {
7533 NULL, /* 00h */
7534 "Open Failure", /* 01h */
7535 "Invalid Scatter Gather List", /* 02h */
7536 "Wrong Relative Offset or Frame Length", /* 03h */
7537 "Frame Transfer Error", /* 04h */
7538 "Transmit Frame Connected Low", /* 05h */
7539 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7540 "SATA Read Log Receive Data Error", /* 07h */
7541 "SATA NCQ Fail All Commands After Error", /* 08h */
7542 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7543 "Receive Frame Invalid Message", /* 0Ah */
7544 "Receive Context Message Valid Error", /* 0Bh */
7545 "Receive Frame Current Frame Error", /* 0Ch */
7546 "SATA Link Down", /* 0Dh */
7547 "Discovery SATA Init W IOS", /* 0Eh */
7548 "Config Invalid Page", /* 0Fh */
7549 "Discovery SATA Init Timeout", /* 10h */
7550 "Reset", /* 11h */
7551 "Abort", /* 12h */
7552 "IO Not Yet Executed", /* 13h */
7553 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007554 "Persistent Reservation Out Not Affiliation "
7555 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007556 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007557 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007558 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007559 NULL, /* 19h */
7560 NULL, /* 1Ah */
7561 NULL, /* 1Bh */
7562 NULL, /* 1Ch */
7563 NULL, /* 1Dh */
7564 NULL, /* 1Eh */
7565 NULL, /* 1Fh */
7566 "Enclosure Management" /* 20h */
7567 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007568 static char *ir_code_str[] = {
7569 "Raid Action Error", /* 00h */
7570 NULL, /* 00h */
7571 NULL, /* 01h */
7572 NULL, /* 02h */
7573 NULL, /* 03h */
7574 NULL, /* 04h */
7575 NULL, /* 05h */
7576 NULL, /* 06h */
7577 NULL /* 07h */
7578 };
7579 static char *raid_sub_code_str[] = {
7580 NULL, /* 00h */
7581 "Volume Creation Failed: Data Passed too "
7582 "Large", /* 01h */
7583 "Volume Creation Failed: Duplicate Volumes "
7584 "Attempted", /* 02h */
7585 "Volume Creation Failed: Max Number "
7586 "Supported Volumes Exceeded", /* 03h */
7587 "Volume Creation Failed: DMA Error", /* 04h */
7588 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7589 "Volume Creation Failed: Error Reading "
7590 "MFG Page 4", /* 06h */
7591 "Volume Creation Failed: Creating Internal "
7592 "Structures", /* 07h */
7593 NULL, /* 08h */
7594 NULL, /* 09h */
7595 NULL, /* 0Ah */
7596 NULL, /* 0Bh */
7597 NULL, /* 0Ch */
7598 NULL, /* 0Dh */
7599 NULL, /* 0Eh */
7600 NULL, /* 0Fh */
7601 "Activation failed: Already Active Volume", /* 10h */
7602 "Activation failed: Unsupported Volume Type", /* 11h */
7603 "Activation failed: Too Many Active Volumes", /* 12h */
7604 "Activation failed: Volume ID in Use", /* 13h */
7605 "Activation failed: Reported Failure", /* 14h */
7606 "Activation failed: Importing a Volume", /* 15h */
7607 NULL, /* 16h */
7608 NULL, /* 17h */
7609 NULL, /* 18h */
7610 NULL, /* 19h */
7611 NULL, /* 1Ah */
7612 NULL, /* 1Bh */
7613 NULL, /* 1Ch */
7614 NULL, /* 1Dh */
7615 NULL, /* 1Eh */
7616 NULL, /* 1Fh */
7617 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7618 "Phys Disk failed: Data Passed too Large", /* 21h */
7619 "Phys Disk failed: DMA Error", /* 22h */
7620 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7621 "Phys Disk failed: Creating Phys Disk Config "
7622 "Page", /* 24h */
7623 NULL, /* 25h */
7624 NULL, /* 26h */
7625 NULL, /* 27h */
7626 NULL, /* 28h */
7627 NULL, /* 29h */
7628 NULL, /* 2Ah */
7629 NULL, /* 2Bh */
7630 NULL, /* 2Ch */
7631 NULL, /* 2Dh */
7632 NULL, /* 2Eh */
7633 NULL, /* 2Fh */
7634 "Compatibility Error: IR Disabled", /* 30h */
7635 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7636 "Compatibility Error: Device not Direct Access "
7637 "Device ", /* 32h */
7638 "Compatibility Error: Removable Device Found", /* 33h */
7639 "Compatibility Error: Device SCSI Version not "
7640 "2 or Higher", /* 34h */
7641 "Compatibility Error: SATA Device, 48 BIT LBA "
7642 "not Supported", /* 35h */
7643 "Compatibility Error: Device doesn't have "
7644 "512 Byte Block Sizes", /* 36h */
7645 "Compatibility Error: Volume Type Check Failed", /* 37h */
7646 "Compatibility Error: Volume Type is "
7647 "Unsupported by FW", /* 38h */
7648 "Compatibility Error: Disk Drive too Small for "
7649 "use in Volume", /* 39h */
7650 "Compatibility Error: Phys Disk for Create "
7651 "Volume not Found", /* 3Ah */
7652 "Compatibility Error: Too Many or too Few "
7653 "Disks for Volume Type", /* 3Bh */
7654 "Compatibility Error: Disk stripe Sizes "
7655 "Must be 64KB", /* 3Ch */
7656 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7657 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007658
7659/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007660/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007661 * mpt_sas_log_info - Log information returned from SAS IOC.
7662 * @ioc: Pointer to MPT_ADAPTER structure
7663 * @log_info: U32 LogInfo reply word from the IOC
7664 *
7665 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007666 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007667static void
7668mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7669{
7670union loginfo_type {
7671 u32 loginfo;
7672 struct {
7673 u32 subcode:16;
7674 u32 code:8;
7675 u32 originator:4;
7676 u32 bus_type:4;
7677 }dw;
7678};
7679 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007680 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007681 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007682 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007683
7684 sas_loginfo.loginfo = log_info;
7685 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007686 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007687 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007688
7689 originator_desc = originator_str[sas_loginfo.dw.originator];
7690
7691 switch (sas_loginfo.dw.originator) {
7692
7693 case 0: /* IOP */
7694 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007695 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007696 code_desc = iop_code_str[sas_loginfo.dw.code];
7697 break;
7698 case 1: /* PL */
7699 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007700 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007701 code_desc = pl_code_str[sas_loginfo.dw.code];
7702 break;
7703 case 2: /* IR */
7704 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007705 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007706 break;
7707 code_desc = ir_code_str[sas_loginfo.dw.code];
7708 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007709 ARRAY_SIZE(raid_sub_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007710 break;
7711 if (sas_loginfo.dw.code == 0)
7712 sub_code_desc =
7713 raid_sub_code_str[sas_loginfo.dw.subcode];
7714 break;
7715 default:
7716 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007717 }
7718
Eric Moorec6c727a2007-01-29 09:44:54 -07007719 if (sub_code_desc != NULL)
7720 printk(MYIOC_s_INFO_FMT
7721 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7722 " SubCode={%s}\n",
7723 ioc->name, log_info, originator_desc, code_desc,
7724 sub_code_desc);
7725 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007726 printk(MYIOC_s_INFO_FMT
7727 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7728 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007729 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007730 sas_loginfo.dw.subcode);
7731 else
7732 printk(MYIOC_s_INFO_FMT
7733 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7734 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007735 ioc->name, log_info, originator_desc,
7736 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007737}
7738
Linus Torvalds1da177e2005-04-16 15:20:36 -07007739/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007740/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007741 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7742 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007743 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007744 * @mf: Pointer to MPT request frame
7745 *
7746 * Refer to lsi/mpi.h.
7747 **/
7748static void
7749mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7750{
7751 Config_t *pReq = (Config_t *)mf;
7752 char extend_desc[EVENT_DESCR_STR_SZ];
7753 char *desc = NULL;
7754 u32 form;
7755 u8 page_type;
7756
7757 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7758 page_type = pReq->ExtPageType;
7759 else
7760 page_type = pReq->Header.PageType;
7761
7762 /*
7763 * ignore invalid page messages for GET_NEXT_HANDLE
7764 */
7765 form = le32_to_cpu(pReq->PageAddress);
7766 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7767 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7768 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7769 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7770 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7771 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7772 return;
7773 }
7774 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7775 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7776 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7777 return;
7778 }
7779
7780 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7781 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7782 page_type, pReq->Header.PageNumber, pReq->Action, form);
7783
7784 switch (ioc_status) {
7785
7786 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7787 desc = "Config Page Invalid Action";
7788 break;
7789
7790 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7791 desc = "Config Page Invalid Type";
7792 break;
7793
7794 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7795 desc = "Config Page Invalid Page";
7796 break;
7797
7798 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7799 desc = "Config Page Invalid Data";
7800 break;
7801
7802 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7803 desc = "Config Page No Defaults";
7804 break;
7805
7806 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7807 desc = "Config Page Can't Commit";
7808 break;
7809 }
7810
7811 if (!desc)
7812 return;
7813
Eric Moore29dd3602007-09-14 18:46:51 -06007814 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7815 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007816}
7817
7818/**
7819 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007820 * @ioc: Pointer to MPT_ADAPTER structure
7821 * @ioc_status: U32 IOCStatus word from IOC
7822 * @mf: Pointer to MPT request frame
7823 *
7824 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007825 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007826static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007827mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007828{
7829 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007830 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007831
7832 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007833
7834/****************************************************************************/
7835/* Common IOCStatus values for all replies */
7836/****************************************************************************/
7837
Linus Torvalds1da177e2005-04-16 15:20:36 -07007838 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7839 desc = "Invalid Function";
7840 break;
7841
7842 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7843 desc = "Busy";
7844 break;
7845
7846 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7847 desc = "Invalid SGL";
7848 break;
7849
7850 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7851 desc = "Internal Error";
7852 break;
7853
7854 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7855 desc = "Reserved";
7856 break;
7857
7858 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7859 desc = "Insufficient Resources";
7860 break;
7861
7862 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7863 desc = "Invalid Field";
7864 break;
7865
7866 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7867 desc = "Invalid State";
7868 break;
7869
Eric Moorec6c727a2007-01-29 09:44:54 -07007870/****************************************************************************/
7871/* Config IOCStatus values */
7872/****************************************************************************/
7873
Linus Torvalds1da177e2005-04-16 15:20:36 -07007874 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7875 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7876 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7877 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7878 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7879 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007880 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007881 break;
7882
Eric Moorec6c727a2007-01-29 09:44:54 -07007883/****************************************************************************/
7884/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7885/* */
7886/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7887/* */
7888/****************************************************************************/
7889
Linus Torvalds1da177e2005-04-16 15:20:36 -07007890 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007891 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007892 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7893 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7894 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7895 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007896 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007897 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007898 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007899 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007900 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007901 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007902 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007903 break;
7904
Eric Moorec6c727a2007-01-29 09:44:54 -07007905/****************************************************************************/
7906/* SCSI Target values */
7907/****************************************************************************/
7908
7909 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7910 desc = "Target: Priority IO";
7911 break;
7912
7913 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7914 desc = "Target: Invalid Port";
7915 break;
7916
7917 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7918 desc = "Target Invalid IO Index:";
7919 break;
7920
7921 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7922 desc = "Target: Aborted";
7923 break;
7924
7925 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7926 desc = "Target: No Conn Retryable";
7927 break;
7928
7929 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7930 desc = "Target: No Connection";
7931 break;
7932
7933 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7934 desc = "Target: Transfer Count Mismatch";
7935 break;
7936
7937 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7938 desc = "Target: STS Data not Sent";
7939 break;
7940
7941 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7942 desc = "Target: Data Offset Error";
7943 break;
7944
7945 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7946 desc = "Target: Too Much Write Data";
7947 break;
7948
7949 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7950 desc = "Target: IU Too Short";
7951 break;
7952
7953 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7954 desc = "Target: ACK NAK Timeout";
7955 break;
7956
7957 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7958 desc = "Target: Nak Received";
7959 break;
7960
7961/****************************************************************************/
7962/* Fibre Channel Direct Access values */
7963/****************************************************************************/
7964
7965 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7966 desc = "FC: Aborted";
7967 break;
7968
7969 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7970 desc = "FC: RX ID Invalid";
7971 break;
7972
7973 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7974 desc = "FC: DID Invalid";
7975 break;
7976
7977 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7978 desc = "FC: Node Logged Out";
7979 break;
7980
7981 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7982 desc = "FC: Exchange Canceled";
7983 break;
7984
7985/****************************************************************************/
7986/* LAN values */
7987/****************************************************************************/
7988
7989 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7990 desc = "LAN: Device not Found";
7991 break;
7992
7993 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7994 desc = "LAN: Device Failure";
7995 break;
7996
7997 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7998 desc = "LAN: Transmit Error";
7999 break;
8000
8001 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
8002 desc = "LAN: Transmit Aborted";
8003 break;
8004
8005 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
8006 desc = "LAN: Receive Error";
8007 break;
8008
8009 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
8010 desc = "LAN: Receive Aborted";
8011 break;
8012
8013 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
8014 desc = "LAN: Partial Packet";
8015 break;
8016
8017 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
8018 desc = "LAN: Canceled";
8019 break;
8020
8021/****************************************************************************/
8022/* Serial Attached SCSI values */
8023/****************************************************************************/
8024
8025 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
8026 desc = "SAS: SMP Request Failed";
8027 break;
8028
8029 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
8030 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07008031 break;
8032
8033 default:
8034 desc = "Others";
8035 break;
8036 }
Eric Moorec6c727a2007-01-29 09:44:54 -07008037
8038 if (!desc)
8039 return;
8040
Eric Moore29dd3602007-09-14 18:46:51 -06008041 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
8042 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008043}
8044
8045/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008046EXPORT_SYMBOL(mpt_attach);
8047EXPORT_SYMBOL(mpt_detach);
8048#ifdef CONFIG_PM
8049EXPORT_SYMBOL(mpt_resume);
8050EXPORT_SYMBOL(mpt_suspend);
8051#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07008052EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008053EXPORT_SYMBOL(mpt_register);
8054EXPORT_SYMBOL(mpt_deregister);
8055EXPORT_SYMBOL(mpt_event_register);
8056EXPORT_SYMBOL(mpt_event_deregister);
8057EXPORT_SYMBOL(mpt_reset_register);
8058EXPORT_SYMBOL(mpt_reset_deregister);
8059EXPORT_SYMBOL(mpt_device_driver_register);
8060EXPORT_SYMBOL(mpt_device_driver_deregister);
8061EXPORT_SYMBOL(mpt_get_msg_frame);
8062EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05308063EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008064EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008065EXPORT_SYMBOL(mpt_send_handshake_request);
8066EXPORT_SYMBOL(mpt_verify_adapter);
8067EXPORT_SYMBOL(mpt_GetIocState);
8068EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008069EXPORT_SYMBOL(mpt_HardResetHandler);
8070EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008071EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008072EXPORT_SYMBOL(mpt_alloc_fw_memory);
8073EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02008074EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07008075EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008076
Linus Torvalds1da177e2005-04-16 15:20:36 -07008077/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008078/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008079 * fusion_init - Fusion MPT base driver initialization routine.
8080 *
8081 * Returns 0 for success, non-zero for failure.
8082 */
8083static int __init
8084fusion_init(void)
8085{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308086 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008087
8088 show_mptmod_ver(my_NAME, my_VERSION);
8089 printk(KERN_INFO COPYRIGHT "\n");
8090
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308091 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
8092 MptCallbacks[cb_idx] = NULL;
8093 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
8094 MptEvHandlers[cb_idx] = NULL;
8095 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008096 }
8097
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008098 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07008099 * EventNotification handling.
8100 */
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05308101 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008102
8103 /* Register for hard reset handling callbacks.
8104 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05308105 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008106
8107#ifdef CONFIG_PROC_FS
8108 (void) procmpt_create();
8109#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008110 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008111}
8112
8113/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008114/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008115 * fusion_exit - Perform driver unload cleanup.
8116 *
8117 * This routine frees all resources associated with each MPT adapter
8118 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
8119 */
8120static void __exit
8121fusion_exit(void)
8122{
8123
Linus Torvalds1da177e2005-04-16 15:20:36 -07008124 mpt_reset_deregister(mpt_base_index);
8125
8126#ifdef CONFIG_PROC_FS
8127 procmpt_destroy();
8128#endif
8129}
8130
Linus Torvalds1da177e2005-04-16 15:20:36 -07008131module_init(fusion_init);
8132module_exit(fusion_exit);