blob: 54326e09629cb5ed416a471e115adebf430374a1 [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 -0700149static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
150
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530151/*
152 * Driver Callback Index's
153 */
154static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
155static u8 last_drv_idx;
156
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
158/*
159 * Forward protos...
160 */
David Howells7d12e782006-10-05 14:55:46 +0100161static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
163static 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);
193static void mpt_timer_expired(unsigned long data);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530194static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
196static 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
210//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
211static int ProcessEventNotification(MPT_ADAPTER *ioc, 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
343 if (ioc->diagPending || !ioc->active)
344 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 */
376 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
377 if (ioc->reset_work_q)
378 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
379 msecs_to_jiffies(MPT_POLLING_INTERVAL));
380 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
381}
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/**
560 * mpt_base_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 * @ioc: Pointer to MPT_ADAPTER structure
562 * @mf: Pointer to original MPT request frame
563 * @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
573mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
574{
575 int freereq = 1;
576 u8 func;
577
Prakash, Sathya436ace72007-07-24 15:42:08 +0530578 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name));
579#ifdef CONFIG_FUSION_LOGGING
580 if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
581 !(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
Eric Moore29dd3602007-09-14 18:46:51 -0600582 dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n",
583 ioc->name, mf));
584 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200586#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
588 func = reply->u.hdr.Function;
Prakash, Sathya436ace72007-07-24 15:42:08 +0530589 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 ioc->name, func));
591
592 if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
593 EventNotificationReply_t *pEvReply = (EventNotificationReply_t *) reply;
594 int evHandlers = 0;
595 int results;
596
597 results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
598 if (results != evHandlers) {
599 /* CHECKME! Any special handling needed here? */
Prakash, Sathya436ace72007-07-24 15:42:08 +0530600 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 ioc->name, evHandlers, results));
602 }
603
604 /*
605 * Hmmm... It seems that EventNotificationReply is an exception
606 * to the rule of one reply per request.
607 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200608 if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 freereq = 0;
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200610 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530611 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200612 ioc->name, pEvReply));
613 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
615#ifdef CONFIG_PROC_FS
616// LogEvent(ioc, pEvReply);
617#endif
618
619 } else if (func == MPI_FUNCTION_EVENT_ACK) {
Prakash, Sathya436ace72007-07-24 15:42:08 +0530620 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 ioc->name));
Moore, Eric592f9c22006-02-02 17:19:47 -0700622 } else if (func == MPI_FUNCTION_CONFIG) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 CONFIGPARMS *pCfg;
624 unsigned long flags;
625
Prakash, Sathya436ace72007-07-24 15:42:08 +0530626 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 ioc->name, mf, reply));
628
629 pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
630
631 if (pCfg) {
632 /* disable timer and remove from linked list */
633 del_timer(&pCfg->timer);
634
635 spin_lock_irqsave(&ioc->FreeQlock, flags);
636 list_del(&pCfg->linkage);
637 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
638
639 /*
640 * If IOC Status is SUCCESS, save the header
641 * and set the status code to GOOD.
642 */
643 pCfg->status = MPT_CONFIG_ERROR;
644 if (reply) {
645 ConfigReply_t *pReply = (ConfigReply_t *)reply;
646 u16 status;
647
648 status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
Eric Moore29dd3602007-09-14 18:46:51 -0600649 dcprintk(ioc, printk(MYIOC_s_NOTE_FMT " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
650 ioc->name, status, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
652 pCfg->status = status;
653 if (status == MPI_IOCSTATUS_SUCCESS) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +0200654 if ((pReply->Header.PageType &
655 MPI_CONFIG_PAGETYPE_MASK) ==
656 MPI_CONFIG_PAGETYPE_EXTENDED) {
657 pCfg->cfghdr.ehdr->ExtPageLength =
658 le16_to_cpu(pReply->ExtPageLength);
659 pCfg->cfghdr.ehdr->ExtPageType =
660 pReply->ExtPageType;
661 }
662 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
663
664 /* If this is a regular header, save PageLength. */
665 /* LMP Do this better so not using a reserved field! */
666 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
667 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
668 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 }
670 }
671
672 /*
673 * Wake up the original calling thread
674 */
675 pCfg->wait_done = 1;
676 wake_up(&mpt_waitq);
677 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200678 } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) {
679 /* we should be always getting a reply frame */
680 memcpy(ioc->persist_reply_frame, reply,
681 min(MPT_DEFAULT_FRAME_SIZE,
682 4*reply->u.reply.MsgLength));
683 del_timer(&ioc->persist_timer);
684 ioc->persist_wait_done = 1;
685 wake_up(&mpt_waitq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 } else {
687 printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n",
688 ioc->name, func);
689 }
690
691 /*
692 * Conditionally tell caller to free the original
693 * EventNotification/EventAck/unexpected request frame!
694 */
695 return freereq;
696}
697
698/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
699/**
700 * mpt_register - Register protocol-specific main callback handler.
701 * @cbfunc: callback function pointer
702 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
703 *
704 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800705 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 * protocol-specific driver must do this before it will be able to
707 * use any IOC resources, such as obtaining request frames.
708 *
709 * NOTES: The SCSI protocol driver currently calls this routine thrice
710 * in order to register separate callbacks; one for "normal" SCSI IO;
711 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
712 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530713 * Returns u8 valued "handle" in the range (and S.O.D. order)
714 * {N,...,7,6,5,...,1} if successful.
715 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
716 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530718u8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
720{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530721 u8 cb_idx;
722 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
724 /*
725 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
726 * (slot/handle 0 is reserved!)
727 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530728 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
729 if (MptCallbacks[cb_idx] == NULL) {
730 MptCallbacks[cb_idx] = cbfunc;
731 MptDriverClass[cb_idx] = dclass;
732 MptEvHandlers[cb_idx] = NULL;
733 last_drv_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 break;
735 }
736 }
737
738 return last_drv_idx;
739}
740
741/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
742/**
743 * mpt_deregister - Deregister a protocol drivers resources.
744 * @cb_idx: previously registered callback handle
745 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800746 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 * module is unloaded.
748 */
749void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530750mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600752 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 MptCallbacks[cb_idx] = NULL;
754 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
755 MptEvHandlers[cb_idx] = NULL;
756
757 last_drv_idx++;
758 }
759}
760
761/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
762/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800763 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 * @cb_idx: previously registered (via mpt_register) callback handle
765 * @ev_cbfunc: callback function
766 *
767 * This routine can be called by one or more protocol-specific drivers
768 * if/when they choose to be notified of MPT events.
769 *
770 * Returns 0 for success.
771 */
772int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530773mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600775 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 return -1;
777
778 MptEvHandlers[cb_idx] = ev_cbfunc;
779 return 0;
780}
781
782/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
783/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800784 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 * @cb_idx: previously registered callback handle
786 *
787 * Each protocol-specific driver should call this routine
788 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800789 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 */
791void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530792mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600794 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 return;
796
797 MptEvHandlers[cb_idx] = NULL;
798}
799
800/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
801/**
802 * mpt_reset_register - Register protocol-specific IOC reset handler.
803 * @cb_idx: previously registered (via mpt_register) callback handle
804 * @reset_func: reset function
805 *
806 * This routine can be called by one or more protocol-specific drivers
807 * if/when they choose to be notified of IOC resets.
808 *
809 * Returns 0 for success.
810 */
811int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530812mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530814 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 return -1;
816
817 MptResetHandlers[cb_idx] = reset_func;
818 return 0;
819}
820
821/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
822/**
823 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
824 * @cb_idx: previously registered callback handle
825 *
826 * Each protocol-specific driver should call this routine
827 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800828 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 */
830void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530831mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530833 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 return;
835
836 MptResetHandlers[cb_idx] = NULL;
837}
838
839/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
840/**
841 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800842 * @dd_cbfunc: driver callbacks struct
843 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 */
845int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530846mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847{
848 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600849 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
Eric Moore8d6d83e2007-09-14 18:47:40 -0600851 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400852 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853
854 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
855
856 /* call per pci device probe entry point */
857 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600858 id = ioc->pcidev->driver ?
859 ioc->pcidev->driver->id_table : NULL;
860 if (dd_cbfunc->probe)
861 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 }
863
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400864 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865}
866
867/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
868/**
869 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800870 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 */
872void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530873mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874{
875 struct mpt_pci_driver *dd_cbfunc;
876 MPT_ADAPTER *ioc;
877
Eric Moore8d6d83e2007-09-14 18:47:40 -0600878 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 return;
880
881 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
882
883 list_for_each_entry(ioc, &ioc_list, list) {
884 if (dd_cbfunc->remove)
885 dd_cbfunc->remove(ioc->pcidev);
886 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200887
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 MptDeviceDriverHandlers[cb_idx] = NULL;
889}
890
891
892/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
893/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800894 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530895 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 * @ioc: Pointer to MPT adapter structure
897 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800898 * Obtain an MPT request frame from the pool (of 1024) that are
899 * allocated per MPT adapter.
900 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 * Returns pointer to a MPT request frame or %NULL if none are available
902 * or IOC is not active.
903 */
904MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530905mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906{
907 MPT_FRAME_HDR *mf;
908 unsigned long flags;
909 u16 req_idx; /* Request index */
910
911 /* validate handle and ioc identifier */
912
913#ifdef MFCNT
914 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600915 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
916 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917#endif
918
919 /* If interrupts are not attached, do not return a request frame */
920 if (!ioc->active)
921 return NULL;
922
923 spin_lock_irqsave(&ioc->FreeQlock, flags);
924 if (!list_empty(&ioc->FreeQ)) {
925 int req_offset;
926
927 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
928 u.frame.linkage.list);
929 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200930 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530931 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
933 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500934 req_idx = req_offset / ioc->req_sz;
935 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600937 /* Default, will be changed if necessary in SG generation */
938 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939#ifdef MFCNT
940 ioc->mfcnt++;
941#endif
942 }
943 else
944 mf = NULL;
945 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
946
947#ifdef MFCNT
948 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600949 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
950 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
951 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 mfcounter++;
953 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600954 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
955 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956#endif
957
Eric Moore29dd3602007-09-14 18:46:51 -0600958 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
959 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 return mf;
961}
962
963/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
964/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800965 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530966 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 * @ioc: Pointer to MPT adapter structure
968 * @mf: Pointer to MPT request frame
969 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800970 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 * specific MPT adapter.
972 */
973void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530974mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975{
976 u32 mf_dma_addr;
977 int req_offset;
978 u16 req_idx; /* Request index */
979
980 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530981 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
983 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500984 req_idx = req_offset / ioc->req_sz;
985 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
987
Prakash, Sathya436ace72007-07-24 15:42:08 +0530988 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200990 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600991 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
992 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
993 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
995}
996
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530997/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800998 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530999 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301000 * @ioc: Pointer to MPT adapter structure
1001 * @mf: Pointer to MPT request frame
1002 *
Randy Dunlap7105a382008-02-29 22:03:27 -08001003 * Send a protocol-specific MPT request frame to an IOC using
1004 * hi-priority request queue.
1005 *
1006 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301007 * specific MPT adapter.
1008 **/
1009void
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301010mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301011{
1012 u32 mf_dma_addr;
1013 int req_offset;
1014 u16 req_idx; /* Request index */
1015
1016 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301017 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +05301018 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
1019 req_idx = req_offset / ioc->req_sz;
1020 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
1021 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
1022
1023 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
1024
1025 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
1026 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
1027 ioc->name, mf_dma_addr, req_idx));
1028 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
1029}
1030
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1032/**
1033 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 * @ioc: Pointer to MPT adapter structure
1035 * @mf: Pointer to MPT request frame
1036 *
1037 * This routine places a MPT request frame back on the MPT adapter's
1038 * FreeQ.
1039 */
1040void
1041mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
1042{
1043 unsigned long flags;
1044
1045 /* Put Request back on FreeQ! */
1046 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001047 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
1049#ifdef MFCNT
1050 ioc->mfcnt--;
1051#endif
1052 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
1053}
1054
1055/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1056/**
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301057 * mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 * @pAddr: virtual address for SGE
1059 * @flagslength: SGE flags and data transfer length
1060 * @dma_addr: Physical address
1061 *
1062 * This routine places a MPT request frame back on the MPT adapter's
1063 * FreeQ.
1064 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301065static void
1066mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067{
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301068 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
1069 pSge->FlagsLength = cpu_to_le32(flagslength);
1070 pSge->Address = cpu_to_le32(dma_addr);
1071}
1072
1073/**
1074 * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
1075 * @pAddr: virtual address for SGE
1076 * @flagslength: SGE flags and data transfer length
1077 * @dma_addr: Physical address
1078 *
1079 * This routine places a MPT request frame back on the MPT adapter's
1080 * FreeQ.
1081 **/
1082static void
1083mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1084{
1085 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1086 pSge->Address.Low = cpu_to_le32
1087 (lower_32_bits((unsigned long)(dma_addr)));
1088 pSge->Address.High = cpu_to_le32
1089 (upper_32_bits((unsigned long)dma_addr));
1090 pSge->FlagsLength = cpu_to_le32
1091 ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1092}
1093
1094/**
1095 * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr
1096 * (1078 workaround).
1097 * @pAddr: virtual address for SGE
1098 * @flagslength: SGE flags and data transfer length
1099 * @dma_addr: Physical address
1100 *
1101 * This routine places a MPT request frame back on the MPT adapter's
1102 * FreeQ.
1103 **/
1104static void
1105mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1106{
1107 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1108 u32 tmp;
1109
1110 pSge->Address.Low = cpu_to_le32
1111 (lower_32_bits((unsigned long)(dma_addr)));
1112 tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
1113
1114 /*
1115 * 1078 errata workaround for the 36GB limitation
1116 */
1117 if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {
1118 flagslength |=
1119 MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
1120 tmp |= (1<<31);
1121 if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
1122 printk(KERN_DEBUG "1078 P0M2 addressing for "
1123 "addr = 0x%llx len = %d\n",
1124 (unsigned long long)dma_addr,
1125 MPI_SGE_LENGTH(flagslength));
1126 }
1127
1128 pSge->Address.High = cpu_to_le32(tmp);
1129 pSge->FlagsLength = cpu_to_le32(
1130 (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1131}
1132
1133/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1134/**
1135 * mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
1136 * @pAddr: virtual address for SGE
1137 * @next: nextChainOffset value (u32's)
1138 * @length: length of next SGL segment
1139 * @dma_addr: Physical address
1140 *
1141 */
1142static void
1143mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1144{
1145 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
1146 pChain->Length = cpu_to_le16(length);
1147 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
1148 pChain->NextChainOffset = next;
1149 pChain->Address = cpu_to_le32(dma_addr);
1150}
1151
1152/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1153/**
1154 * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
1155 * @pAddr: virtual address for SGE
1156 * @next: nextChainOffset value (u32's)
1157 * @length: length of next SGL segment
1158 * @dma_addr: Physical address
1159 *
1160 */
1161static void
1162mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1163{
1164 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 u32 tmp = dma_addr & 0xFFFFFFFF;
1166
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301167 pChain->Length = cpu_to_le16(length);
1168 pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
1169 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301171 pChain->NextChainOffset = next;
1172
1173 pChain->Address.Low = cpu_to_le32(tmp);
1174 tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
1175 pChain->Address.High = cpu_to_le32(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176}
1177
1178/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1179/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001180 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301181 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 * @ioc: Pointer to MPT adapter structure
1183 * @reqBytes: Size of the request in bytes
1184 * @req: Pointer to MPT request frame
1185 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1186 *
1187 * This routine is used exclusively to send MptScsiTaskMgmt
1188 * requests since they are required to be sent via doorbell handshake.
1189 *
1190 * NOTE: It is the callers responsibility to byte-swap fields in the
1191 * request which are greater than 1 byte in size.
1192 *
1193 * Returns 0 for success, non-zero for failure.
1194 */
1195int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301196mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197{
Eric Moorecd2c6192007-01-29 09:47:47 -07001198 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 u8 *req_as_bytes;
1200 int ii;
1201
1202 /* State is known to be good upon entering
1203 * this function so issue the bus reset
1204 * request.
1205 */
1206
1207 /*
1208 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1209 * setting cb_idx/req_idx. But ONLY if this request
1210 * is in proper (pre-alloc'd) request buffer range...
1211 */
1212 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1213 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1214 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1215 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301216 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 }
1218
1219 /* Make sure there are no doorbells */
1220 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001221
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1223 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1224 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1225
1226 /* Wait for IOC doorbell int */
1227 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1228 return ii;
1229 }
1230
1231 /* Read doorbell and check for active bit */
1232 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1233 return -5;
1234
Eric Moore29dd3602007-09-14 18:46:51 -06001235 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001236 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237
1238 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1239
1240 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1241 return -2;
1242 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001243
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 /* Send request via doorbell handshake */
1245 req_as_bytes = (u8 *) req;
1246 for (ii = 0; ii < reqBytes/4; ii++) {
1247 u32 word;
1248
1249 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1250 (req_as_bytes[(ii*4) + 1] << 8) |
1251 (req_as_bytes[(ii*4) + 2] << 16) |
1252 (req_as_bytes[(ii*4) + 3] << 24));
1253 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1254 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1255 r = -3;
1256 break;
1257 }
1258 }
1259
1260 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1261 r = 0;
1262 else
1263 r = -4;
1264
1265 /* Make sure there are no doorbells */
1266 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001267
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 return r;
1269}
1270
1271/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1272/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001273 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001274 * @ioc: Pointer to MPT adapter structure
1275 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001276 * @sleepFlag: Specifies whether the process can sleep
1277 *
1278 * Provides mechanism for the host driver to control the IOC's
1279 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001280 *
1281 * Access Control Value - bits[15:12]
1282 * 0h Reserved
1283 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1284 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1285 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1286 *
1287 * Returns 0 for success, non-zero for failure.
1288 */
1289
1290static int
1291mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1292{
1293 int r = 0;
1294
1295 /* return if in use */
1296 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1297 & MPI_DOORBELL_ACTIVE)
1298 return -1;
1299
1300 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1301
1302 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1303 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1304 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1305 (access_control_value<<12)));
1306
1307 /* Wait for IOC to clear Doorbell Status bit */
1308 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1309 return -2;
1310 }else
1311 return 0;
1312}
1313
1314/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1315/**
1316 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001317 * @ioc: Pointer to pointer to IOC adapter
1318 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001319 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001320 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001321 * Returns 0 for success, non-zero for failure.
1322 */
1323static int
1324mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1325{
1326 char *psge;
1327 int flags_length;
1328 u32 host_page_buffer_sz=0;
1329
1330 if(!ioc->HostPageBuffer) {
1331
1332 host_page_buffer_sz =
1333 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1334
1335 if(!host_page_buffer_sz)
1336 return 0; /* fw doesn't need any host buffers */
1337
1338 /* spin till we get enough memory */
1339 while(host_page_buffer_sz > 0) {
1340
1341 if((ioc->HostPageBuffer = pci_alloc_consistent(
1342 ioc->pcidev,
1343 host_page_buffer_sz,
1344 &ioc->HostPageBuffer_dma)) != NULL) {
1345
Prakash, Sathya436ace72007-07-24 15:42:08 +05301346 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001347 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001348 ioc->name, ioc->HostPageBuffer,
1349 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001350 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001351 ioc->alloc_total += host_page_buffer_sz;
1352 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1353 break;
1354 }
1355
1356 host_page_buffer_sz -= (4*1024);
1357 }
1358 }
1359
1360 if(!ioc->HostPageBuffer) {
1361 printk(MYIOC_s_ERR_FMT
1362 "Failed to alloc memory for host_page_buffer!\n",
1363 ioc->name);
1364 return -999;
1365 }
1366
1367 psge = (char *)&ioc_init->HostPageBufferSGE;
1368 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1369 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1370 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1371 MPI_SGE_FLAGS_HOST_TO_IOC |
1372 MPI_SGE_FLAGS_END_OF_BUFFER;
1373 if (sizeof(dma_addr_t) == sizeof(u64)) {
1374 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1375 }
1376 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1377 flags_length |= ioc->HostPageBuffer_sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301378 ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001379 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1380
1381return 0;
1382}
1383
1384/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1385/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001386 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 * @iocid: IOC unique identifier (integer)
1388 * @iocpp: Pointer to pointer to IOC adapter
1389 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001390 * Given a unique IOC identifier, set pointer to the associated MPT
1391 * adapter structure.
1392 *
1393 * Returns iocid and sets iocpp if iocid is found.
1394 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 */
1396int
1397mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1398{
1399 MPT_ADAPTER *ioc;
1400
1401 list_for_each_entry(ioc,&ioc_list,list) {
1402 if (ioc->id == iocid) {
1403 *iocpp =ioc;
1404 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001407
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 *iocpp = NULL;
1409 return -1;
1410}
1411
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301412/**
1413 * mpt_get_product_name - returns product string
1414 * @vendor: pci vendor id
1415 * @device: pci device id
1416 * @revision: pci revision id
1417 * @prod_name: string returned
1418 *
1419 * Returns product string displayed when driver loads,
1420 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1421 *
1422 **/
1423static void
1424mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1425{
1426 char *product_str = NULL;
1427
1428 if (vendor == PCI_VENDOR_ID_BROCADE) {
1429 switch (device)
1430 {
1431 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1432 switch (revision)
1433 {
1434 case 0x00:
1435 product_str = "BRE040 A0";
1436 break;
1437 case 0x01:
1438 product_str = "BRE040 A1";
1439 break;
1440 default:
1441 product_str = "BRE040";
1442 break;
1443 }
1444 break;
1445 }
1446 goto out;
1447 }
1448
1449 switch (device)
1450 {
1451 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1452 product_str = "LSIFC909 B1";
1453 break;
1454 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1455 product_str = "LSIFC919 B0";
1456 break;
1457 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1458 product_str = "LSIFC929 B0";
1459 break;
1460 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1461 if (revision < 0x80)
1462 product_str = "LSIFC919X A0";
1463 else
1464 product_str = "LSIFC919XL A1";
1465 break;
1466 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1467 if (revision < 0x80)
1468 product_str = "LSIFC929X A0";
1469 else
1470 product_str = "LSIFC929XL A1";
1471 break;
1472 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1473 product_str = "LSIFC939X A1";
1474 break;
1475 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1476 product_str = "LSIFC949X A1";
1477 break;
1478 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1479 switch (revision)
1480 {
1481 case 0x00:
1482 product_str = "LSIFC949E A0";
1483 break;
1484 case 0x01:
1485 product_str = "LSIFC949E A1";
1486 break;
1487 default:
1488 product_str = "LSIFC949E";
1489 break;
1490 }
1491 break;
1492 case MPI_MANUFACTPAGE_DEVID_53C1030:
1493 switch (revision)
1494 {
1495 case 0x00:
1496 product_str = "LSI53C1030 A0";
1497 break;
1498 case 0x01:
1499 product_str = "LSI53C1030 B0";
1500 break;
1501 case 0x03:
1502 product_str = "LSI53C1030 B1";
1503 break;
1504 case 0x07:
1505 product_str = "LSI53C1030 B2";
1506 break;
1507 case 0x08:
1508 product_str = "LSI53C1030 C0";
1509 break;
1510 case 0x80:
1511 product_str = "LSI53C1030T A0";
1512 break;
1513 case 0x83:
1514 product_str = "LSI53C1030T A2";
1515 break;
1516 case 0x87:
1517 product_str = "LSI53C1030T A3";
1518 break;
1519 case 0xc1:
1520 product_str = "LSI53C1020A A1";
1521 break;
1522 default:
1523 product_str = "LSI53C1030";
1524 break;
1525 }
1526 break;
1527 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1528 switch (revision)
1529 {
1530 case 0x03:
1531 product_str = "LSI53C1035 A2";
1532 break;
1533 case 0x04:
1534 product_str = "LSI53C1035 B0";
1535 break;
1536 default:
1537 product_str = "LSI53C1035";
1538 break;
1539 }
1540 break;
1541 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1542 switch (revision)
1543 {
1544 case 0x00:
1545 product_str = "LSISAS1064 A1";
1546 break;
1547 case 0x01:
1548 product_str = "LSISAS1064 A2";
1549 break;
1550 case 0x02:
1551 product_str = "LSISAS1064 A3";
1552 break;
1553 case 0x03:
1554 product_str = "LSISAS1064 A4";
1555 break;
1556 default:
1557 product_str = "LSISAS1064";
1558 break;
1559 }
1560 break;
1561 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1562 switch (revision)
1563 {
1564 case 0x00:
1565 product_str = "LSISAS1064E A0";
1566 break;
1567 case 0x01:
1568 product_str = "LSISAS1064E B0";
1569 break;
1570 case 0x02:
1571 product_str = "LSISAS1064E B1";
1572 break;
1573 case 0x04:
1574 product_str = "LSISAS1064E B2";
1575 break;
1576 case 0x08:
1577 product_str = "LSISAS1064E B3";
1578 break;
1579 default:
1580 product_str = "LSISAS1064E";
1581 break;
1582 }
1583 break;
1584 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1585 switch (revision)
1586 {
1587 case 0x00:
1588 product_str = "LSISAS1068 A0";
1589 break;
1590 case 0x01:
1591 product_str = "LSISAS1068 B0";
1592 break;
1593 case 0x02:
1594 product_str = "LSISAS1068 B1";
1595 break;
1596 default:
1597 product_str = "LSISAS1068";
1598 break;
1599 }
1600 break;
1601 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1602 switch (revision)
1603 {
1604 case 0x00:
1605 product_str = "LSISAS1068E A0";
1606 break;
1607 case 0x01:
1608 product_str = "LSISAS1068E B0";
1609 break;
1610 case 0x02:
1611 product_str = "LSISAS1068E B1";
1612 break;
1613 case 0x04:
1614 product_str = "LSISAS1068E B2";
1615 break;
1616 case 0x08:
1617 product_str = "LSISAS1068E B3";
1618 break;
1619 default:
1620 product_str = "LSISAS1068E";
1621 break;
1622 }
1623 break;
1624 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1625 switch (revision)
1626 {
1627 case 0x00:
1628 product_str = "LSISAS1078 A0";
1629 break;
1630 case 0x01:
1631 product_str = "LSISAS1078 B0";
1632 break;
1633 case 0x02:
1634 product_str = "LSISAS1078 C0";
1635 break;
1636 case 0x03:
1637 product_str = "LSISAS1078 C1";
1638 break;
1639 case 0x04:
1640 product_str = "LSISAS1078 C2";
1641 break;
1642 default:
1643 product_str = "LSISAS1078";
1644 break;
1645 }
1646 break;
1647 }
1648
1649 out:
1650 if (product_str)
1651 sprintf(prod_name, "%s", product_str);
1652}
1653
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301654/**
1655 * mpt_mapresources - map in memory mapped io
1656 * @ioc: Pointer to pointer to IOC adapter
1657 *
1658 **/
1659static int
1660mpt_mapresources(MPT_ADAPTER *ioc)
1661{
1662 u8 __iomem *mem;
1663 int ii;
1664 unsigned long mem_phys;
1665 unsigned long port;
1666 u32 msize;
1667 u32 psize;
1668 u8 revision;
1669 int r = -ENODEV;
1670 struct pci_dev *pdev;
1671
1672 pdev = ioc->pcidev;
1673 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1674 if (pci_enable_device_mem(pdev)) {
1675 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1676 "failed\n", ioc->name);
1677 return r;
1678 }
1679 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1680 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1681 "MEM failed\n", ioc->name);
1682 return r;
1683 }
1684
1685 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1686
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301687 if (sizeof(dma_addr_t) > 4) {
1688 const uint64_t required_mask = dma_get_required_mask
1689 (&pdev->dev);
1690 if (required_mask > DMA_BIT_MASK(32)
1691 && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
1692 && !pci_set_consistent_dma_mask(pdev,
1693 DMA_BIT_MASK(64))) {
1694 ioc->dma_mask = DMA_BIT_MASK(64);
1695 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1696 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1697 ioc->name));
1698 } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1699 && !pci_set_consistent_dma_mask(pdev,
1700 DMA_BIT_MASK(32))) {
1701 ioc->dma_mask = DMA_BIT_MASK(32);
1702 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1703 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1704 ioc->name));
1705 } else {
1706 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1707 ioc->name, pci_name(pdev));
1708 return r;
1709 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301710 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301711 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1712 && !pci_set_consistent_dma_mask(pdev,
1713 DMA_BIT_MASK(32))) {
1714 ioc->dma_mask = DMA_BIT_MASK(32);
1715 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1716 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1717 ioc->name));
1718 } else {
1719 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1720 ioc->name, pci_name(pdev));
1721 return r;
1722 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301723 }
1724
1725 mem_phys = msize = 0;
1726 port = psize = 0;
1727 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1728 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1729 if (psize)
1730 continue;
1731 /* Get I/O space! */
1732 port = pci_resource_start(pdev, ii);
1733 psize = pci_resource_len(pdev, ii);
1734 } else {
1735 if (msize)
1736 continue;
1737 /* Get memmap */
1738 mem_phys = pci_resource_start(pdev, ii);
1739 msize = pci_resource_len(pdev, ii);
1740 }
1741 }
1742 ioc->mem_size = msize;
1743
1744 mem = NULL;
1745 /* Get logical ptr for PciMem0 space */
1746 /*mem = ioremap(mem_phys, msize);*/
1747 mem = ioremap(mem_phys, msize);
1748 if (mem == NULL) {
1749 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1750 " memory!\n", ioc->name);
1751 return -EINVAL;
1752 }
1753 ioc->memmap = mem;
1754 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n",
1755 ioc->name, mem, mem_phys));
1756
1757 ioc->mem_phys = mem_phys;
1758 ioc->chip = (SYSIF_REGS __iomem *)mem;
1759
1760 /* Save Port IO values in case we need to do downloadboot */
1761 ioc->pio_mem_phys = port;
1762 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1763
1764 return 0;
1765}
1766
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001768/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001769 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001771 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 *
1773 * This routine performs all the steps necessary to bring the IOC of
1774 * a MPT adapter to a OPERATIONAL state. This includes registering
1775 * memory regions, registering the interrupt, and allocating request
1776 * and reply memory pools.
1777 *
1778 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1779 * MPT adapter.
1780 *
1781 * Returns 0 for success, non-zero for failure.
1782 *
1783 * TODO: Add support for polled controllers
1784 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001785int
1786mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787{
1788 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301789 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 u8 revision;
1792 u8 pcixcmd;
1793 static int mpt_ids = 0;
1794#ifdef CONFIG_PROC_FS
1795 struct proc_dir_entry *dent, *ent;
1796#endif
1797
Jesper Juhl56876192007-08-10 14:50:51 -07001798 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1799 if (ioc == NULL) {
1800 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1801 return -ENOMEM;
1802 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301803
Eric Moore29dd3602007-09-14 18:46:51 -06001804 ioc->id = mpt_ids++;
1805 sprintf(ioc->name, "ioc%d", ioc->id);
Jesper Juhl56876192007-08-10 14:50:51 -07001806
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301807 /*
1808 * set initial debug level
1809 * (refer to mptdebug.h)
1810 *
1811 */
1812 ioc->debug_level = mpt_debug_level;
1813 if (mpt_debug_level)
1814 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301815
Eric Moore29dd3602007-09-14 18:46:51 -06001816 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001817
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301818 ioc->pcidev = pdev;
1819 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001820 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 return r;
1822 }
1823
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301824 /*
1825 * Setting up proper handlers for scatter gather handling
1826 */
1827 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
1828 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
1829 ioc->add_sge = &mpt_add_sge_64bit_1078;
1830 else
1831 ioc->add_sge = &mpt_add_sge_64bit;
1832 ioc->add_chain = &mpt_add_chain_64bit;
1833 ioc->sg_addr_size = 8;
1834 } else {
1835 ioc->add_sge = &mpt_add_sge;
1836 ioc->add_chain = &mpt_add_chain;
1837 ioc->sg_addr_size = 4;
1838 }
1839 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
1840
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 ioc->alloc_total = sizeof(MPT_ADAPTER);
1842 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1843 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001844
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 ioc->pcidev = pdev;
1846 ioc->diagPending = 0;
1847 spin_lock_init(&ioc->diagLock);
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001848 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849
1850 /* Initialize the event logging.
1851 */
1852 ioc->eventTypes = 0; /* None */
1853 ioc->eventContext = 0;
1854 ioc->eventLogSize = 0;
1855 ioc->events = NULL;
1856
1857#ifdef MFCNT
1858 ioc->mfcnt = 0;
1859#endif
1860
1861 ioc->cached_fw = NULL;
1862
1863 /* Initilize SCSI Config Data structure
1864 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001865 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866
1867 /* Initialize the running configQ head.
1868 */
1869 INIT_LIST_HEAD(&ioc->configQ);
1870
Michael Reed05e8ec12006-01-13 14:31:54 -06001871 /* Initialize the fc rport list head.
1872 */
1873 INIT_LIST_HEAD(&ioc->fc_rports);
1874
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 /* Find lookup slot. */
1876 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001877
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301878
1879 /* Initialize workqueue */
1880 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
1881 spin_lock_init(&ioc->fault_reset_work_lock);
1882
Kay Sieversaab0de22008-05-02 06:02:41 +02001883 snprintf(ioc->reset_work_q_name, sizeof(ioc->reset_work_q_name),
1884 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301885 ioc->reset_work_q =
1886 create_singlethread_workqueue(ioc->reset_work_q_name);
1887 if (!ioc->reset_work_q) {
1888 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1889 ioc->name);
1890 pci_release_selected_regions(pdev, ioc->bars);
1891 kfree(ioc);
1892 return -ENOMEM;
1893 }
1894
Eric Moore29dd3602007-09-14 18:46:51 -06001895 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1896 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301898 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1899 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1900
1901 switch (pdev->device)
1902 {
1903 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1904 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1905 ioc->errata_flag_1064 = 1;
1906 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1907 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1908 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1909 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301911 break;
1912
1913 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 /* 929X Chip Fix. Set Split transactions level
1916 * for PCIX. Set MOST bits to zero.
1917 */
1918 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1919 pcixcmd &= 0x8F;
1920 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1921 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 /* 929XL Chip Fix. Set MMRBC to 0x08.
1923 */
1924 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1925 pcixcmd |= 0x08;
1926 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1927 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301929 break;
1930
1931 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 /* 919X Chip Fix. Set Split transactions level
1933 * for PCIX. Set MOST bits to zero.
1934 */
1935 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1936 pcixcmd &= 0x8F;
1937 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001938 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301939 break;
1940
1941 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 /* 1030 Chip Fix. Disable Split transactions
1943 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1944 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 if (revision < C0_1030) {
1946 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1947 pcixcmd &= 0x8F;
1948 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1949 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301950
1951 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001952 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301953 break;
1954
1955 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1956 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001957 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301958
1959 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1960 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1961 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001962 ioc->bus_type = SAS;
1963 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301965
Kashyap, Desaie3829682009-01-08 14:27:16 +05301966 switch (ioc->bus_type) {
1967
1968 case SAS:
1969 ioc->msi_enable = mpt_msi_enable_sas;
1970 break;
1971
1972 case SPI:
1973 ioc->msi_enable = mpt_msi_enable_spi;
1974 break;
1975
1976 case FC:
1977 ioc->msi_enable = mpt_msi_enable_fc;
1978 break;
1979
1980 default:
1981 ioc->msi_enable = 0;
1982 break;
1983 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001984 if (ioc->errata_flag_1064)
1985 pci_disable_io_access(pdev);
1986
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 spin_lock_init(&ioc->FreeQlock);
1988
1989 /* Disable all! */
1990 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1991 ioc->active = 0;
1992 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1993
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301994 /* Set IOC ptr in the pcidev's driver data. */
1995 pci_set_drvdata(ioc->pcidev, ioc);
1996
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 /* Set lookup ptr. */
1998 list_add_tail(&ioc->list, &ioc_list);
1999
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002000 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 */
2002 mpt_detect_bound_ports(ioc, pdev);
2003
James Bottomleyc92f2222006-03-01 09:02:49 -06002004 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2005 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06002006 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
2007 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06002008
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07002010 if (ioc->alt_ioc)
2011 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302012 iounmap(ioc->memmap);
2013 if (r != -5)
2014 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302015
2016 destroy_workqueue(ioc->reset_work_q);
2017 ioc->reset_work_q = NULL;
2018
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 kfree(ioc);
2020 pci_set_drvdata(pdev, NULL);
2021 return r;
2022 }
2023
2024 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002025 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302026 if(MptDeviceDriverHandlers[cb_idx] &&
2027 MptDeviceDriverHandlers[cb_idx]->probe) {
2028 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 }
2030 }
2031
2032#ifdef CONFIG_PROC_FS
2033 /*
2034 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
2035 */
2036 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
2037 if (dent) {
2038 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
2039 if (ent) {
2040 ent->read_proc = procmpt_iocinfo_read;
2041 ent->data = ioc;
2042 }
2043 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
2044 if (ent) {
2045 ent->read_proc = procmpt_summary_read;
2046 ent->data = ioc;
2047 }
2048 }
2049#endif
2050
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302051 if (!ioc->alt_ioc)
2052 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
2053 msecs_to_jiffies(MPT_POLLING_INTERVAL));
2054
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 return 0;
2056}
2057
2058/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002059/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002060 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 */
2063
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002064void
2065mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066{
2067 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2068 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302069 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302070 unsigned long flags;
2071 struct workqueue_struct *wq;
2072
2073 /*
2074 * Stop polling ioc for fault condition
2075 */
2076 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
2077 wq = ioc->reset_work_q;
2078 ioc->reset_work_q = NULL;
2079 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
2080 cancel_delayed_work(&ioc->fault_reset_work);
2081 destroy_workqueue(wq);
2082
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083
2084 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2085 remove_proc_entry(pname, NULL);
2086 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2087 remove_proc_entry(pname, NULL);
2088 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2089 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002090
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002092 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302093 if(MptDeviceDriverHandlers[cb_idx] &&
2094 MptDeviceDriverHandlers[cb_idx]->remove) {
2095 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 }
2097 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002098
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 /* Disable interrupts! */
2100 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2101
2102 ioc->active = 0;
2103 synchronize_irq(pdev->irq);
2104
2105 /* Clear any lingering interrupt */
2106 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2107
2108 CHIPREG_READ32(&ioc->chip->IntStatus);
2109
2110 mpt_adapter_dispose(ioc);
2111
2112 pci_set_drvdata(pdev, NULL);
2113}
2114
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115/**************************************************************************
2116 * Power Management
2117 */
2118#ifdef CONFIG_PM
2119/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002120/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002121 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002122 * @pdev: Pointer to pci_dev structure
2123 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002125int
2126mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127{
2128 u32 device_state;
2129 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302131 device_state = pci_choose_state(pdev, state);
2132 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2133 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2134 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135
2136 /* put ioc into READY_STATE */
2137 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2138 printk(MYIOC_s_ERR_FMT
2139 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2140 }
2141
2142 /* disable interrupts */
2143 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2144 ioc->active = 0;
2145
2146 /* Clear any lingering interrupt */
2147 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2148
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302149 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002150 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302151 pci_disable_msi(ioc->pcidev);
2152 ioc->pci_irq = -1;
2153 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302155 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 return 0;
2158}
2159
2160/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002161/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002162 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002163 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002165int
2166mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167{
2168 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2169 u32 device_state = pdev->current_state;
2170 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302171 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002172
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302173 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2174 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2175 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302177 pci_set_power_state(pdev, PCI_D0);
2178 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302180 ioc->pcidev = pdev;
2181 err = mpt_mapresources(ioc);
2182 if (err)
2183 return err;
2184
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302185 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2186 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2187 ioc->add_sge = &mpt_add_sge_64bit_1078;
2188 else
2189 ioc->add_sge = &mpt_add_sge_64bit;
2190 ioc->add_chain = &mpt_add_chain_64bit;
2191 ioc->sg_addr_size = 8;
2192 } else {
2193
2194 ioc->add_sge = &mpt_add_sge;
2195 ioc->add_chain = &mpt_add_chain;
2196 ioc->sg_addr_size = 4;
2197 }
2198 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2199
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302200 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2201 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2202 CHIPREG_READ32(&ioc->chip->Doorbell));
2203
2204 /*
2205 * Errata workaround for SAS pci express:
2206 * Upon returning to the D0 state, the contents of the doorbell will be
2207 * stale data, and this will incorrectly signal to the host driver that
2208 * the firmware is ready to process mpt commands. The workaround is
2209 * to issue a diagnostic reset.
2210 */
2211 if (ioc->bus_type == SAS && (pdev->device ==
2212 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2213 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2214 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2215 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2216 ioc->name);
2217 goto out;
2218 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302219 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220
2221 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302222 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2223 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2224 CAN_SLEEP);
2225 if (recovery_state != 0)
2226 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2227 "error:[%x]\n", ioc->name, recovery_state);
2228 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302230 "pci-resume: success\n", ioc->name);
2231 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302233
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234}
2235#endif
2236
James Bottomley4ff42a62006-05-17 18:06:52 -05002237static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302238mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002239{
2240 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2241 ioc->bus_type != SPI) ||
2242 (MptDriverClass[index] == MPTFC_DRIVER &&
2243 ioc->bus_type != FC) ||
2244 (MptDriverClass[index] == MPTSAS_DRIVER &&
2245 ioc->bus_type != SAS))
2246 /* make sure we only call the relevant reset handler
2247 * for the bus */
2248 return 0;
2249 return (MptResetHandlers[index])(ioc, reset_phase);
2250}
2251
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002253/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2255 * @ioc: Pointer to MPT adapter structure
2256 * @reason: Event word / reason
2257 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2258 *
2259 * This routine performs all the steps necessary to bring the IOC
2260 * to a OPERATIONAL state.
2261 *
2262 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2263 * MPT adapter.
2264 *
2265 * Returns:
2266 * 0 for success
2267 * -1 if failed to get board READY
2268 * -2 if READY but IOCFacts Failed
2269 * -3 if READY but PrimeIOCFifos Failed
2270 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302271 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302272 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 */
2274static int
2275mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2276{
2277 int hard_reset_done = 0;
2278 int alt_ioc_ready = 0;
2279 int hard;
2280 int rc=0;
2281 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302282 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 int handlers;
2284 int ret = 0;
2285 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002286 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302287 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288
Eric Moore29dd3602007-09-14 18:46:51 -06002289 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2290 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291
2292 /* Disable reply interrupts (also blocks FreeQ) */
2293 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2294 ioc->active = 0;
2295
2296 if (ioc->alt_ioc) {
2297 if (ioc->alt_ioc->active)
2298 reset_alt_ioc_active = 1;
2299
2300 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
2301 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
2302 ioc->alt_ioc->active = 0;
2303 }
2304
2305 hard = 1;
2306 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2307 hard = 0;
2308
2309 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2310 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002311 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2312 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313
2314 if (reset_alt_ioc_active && ioc->alt_ioc) {
2315 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002316 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2317 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002318 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 ioc->alt_ioc->active = 1;
2320 }
2321
2322 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002323 printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 }
2325 return -1;
2326 }
2327
2328 /* hard_reset_done = 0 if a soft reset was performed
2329 * and 1 if a hard reset was performed.
2330 */
2331 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2332 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2333 alt_ioc_ready = 1;
2334 else
Eric Moore29dd3602007-09-14 18:46:51 -06002335 printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 }
2337
2338 for (ii=0; ii<5; ii++) {
2339 /* Get IOC facts! Allow 5 retries */
2340 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2341 break;
2342 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002343
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344
2345 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002346 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2347 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 ret = -2;
2349 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2350 MptDisplayIocCapabilities(ioc);
2351 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002352
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 if (alt_ioc_ready) {
2354 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302355 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002356 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 /* Retry - alt IOC was initialized once
2358 */
2359 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2360 }
2361 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302362 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002363 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 alt_ioc_ready = 0;
2365 reset_alt_ioc_active = 0;
2366 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2367 MptDisplayIocCapabilities(ioc->alt_ioc);
2368 }
2369 }
2370
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302371 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2372 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2373 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2374 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2375 IORESOURCE_IO);
2376 if (pci_enable_device(ioc->pcidev))
2377 return -5;
2378 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2379 "mpt"))
2380 return -5;
2381 }
2382
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002383 /*
2384 * Device is reset now. It must have de-asserted the interrupt line
2385 * (if it was asserted) and it should be safe to register for the
2386 * interrupt now.
2387 */
2388 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2389 ioc->pci_irq = -1;
2390 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302391 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002392 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002393 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302394 else
2395 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002396 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002397 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002398 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002399 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Eric Moore29dd3602007-09-14 18:46:51 -06002400 "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302401 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002402 pci_disable_msi(ioc->pcidev);
2403 return -EBUSY;
2404 }
2405 irq_allocated = 1;
2406 ioc->pci_irq = ioc->pcidev->irq;
2407 pci_set_master(ioc->pcidev); /* ?? */
Eric Moore29dd3602007-09-14 18:46:51 -06002408 dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
2409 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002410 }
2411 }
2412
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 /* Prime reply & request queues!
2414 * (mucho alloc's) Must be done prior to
2415 * init as upper addresses are needed for init.
2416 * If fails, continue with alt-ioc processing
2417 */
2418 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2419 ret = -3;
2420
2421 /* May need to check/upload firmware & data here!
2422 * If fails, continue with alt-ioc processing
2423 */
2424 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2425 ret = -4;
2426// NEW!
2427 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002428 printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
2429 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 alt_ioc_ready = 0;
2431 reset_alt_ioc_active = 0;
2432 }
2433
2434 if (alt_ioc_ready) {
2435 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2436 alt_ioc_ready = 0;
2437 reset_alt_ioc_active = 0;
Eric Moore29dd3602007-09-14 18:46:51 -06002438 printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
2439 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 }
2441 }
2442
2443 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2444 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302445 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002446 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447
2448 /* Controller is not operational, cannot do upload
2449 */
2450 if (ret == 0) {
2451 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002452 if (rc == 0) {
2453 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2454 /*
2455 * Maintain only one pointer to FW memory
2456 * so there will not be two attempt to
2457 * downloadboot onboard dual function
2458 * chips (mpt_adapter_disable,
2459 * mpt_diag_reset)
2460 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302461 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002462 "mpt_upload: alt_%s has cached_fw=%p \n",
2463 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302464 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002465 }
2466 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002467 printk(MYIOC_s_WARN_FMT
2468 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302469 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002470 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 }
2472 }
2473 }
2474
2475 if (ret == 0) {
2476 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002477 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 ioc->active = 1;
2479 }
2480
2481 if (reset_alt_ioc_active && ioc->alt_ioc) {
2482 /* (re)Enable alt-IOC! (reply interrupt) */
Eric Moore29dd3602007-09-14 18:46:51 -06002483 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
2484 ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002485 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 ioc->alt_ioc->active = 1;
2487 }
2488
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002489 /* Enable MPT base driver management of EventNotification
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 * and EventAck handling.
2491 */
2492 if ((ret == 0) && (!ioc->facts.EventState))
2493 (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */
2494
2495 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2496 (void) SendEventNotification(ioc->alt_ioc, 1); /* 1=Enable EventNotification */
2497
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002498 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2500 * recursive scenario; GetLanConfigPages times out, timer expired
2501 * routine calls HardResetHandler, which calls into here again,
2502 * and we try GetLanConfigPages again...
2503 */
2504 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002505
2506 /*
2507 * Initalize link list for inactive raid volumes.
2508 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002509 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002510 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2511
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002512 if (ioc->bus_type == SAS) {
2513
2514 /* clear persistency table */
2515 if(ioc->facts.IOCExceptions &
2516 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2517 ret = mptbase_sas_persist_operation(ioc,
2518 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2519 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002520 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002521 }
2522
2523 /* Find IM volumes
2524 */
2525 mpt_findImVolumes(ioc);
2526
2527 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2529 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2530 /*
2531 * Pre-fetch the ports LAN MAC address!
2532 * (LANPage1_t stuff)
2533 */
2534 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302535 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2536 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002537 "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2538 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302539
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 }
2541 } else {
2542 /* Get NVRAM and adapter maximums from SPP 0 and 2
2543 */
2544 mpt_GetScsiPortSettings(ioc, 0);
2545
2546 /* Get version and length of SDP 1
2547 */
2548 mpt_readScsiDevicePageHeaders(ioc, 0);
2549
2550 /* Find IM volumes
2551 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002552 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 mpt_findImVolumes(ioc);
2554
2555 /* Check, and possibly reset, the coalescing value
2556 */
2557 mpt_read_ioc_pg_1(ioc);
2558
2559 mpt_read_ioc_pg_4(ioc);
2560 }
2561
2562 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302563 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 }
2565
2566 /*
2567 * Call each currently registered protocol IOC reset handler
2568 * with post-reset indication.
2569 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2570 * MptResetHandlers[] registered yet.
2571 */
2572 if (hard_reset_done) {
2573 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302574 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2575 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302576 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002577 "Calling IOC post_reset handler #%d\n",
2578 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302579 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 handlers++;
2581 }
2582
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302583 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302584 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002585 "Calling IOC post_reset handler #%d\n",
2586 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302587 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 handlers++;
2589 }
2590 }
2591 /* FIXME? Examine results here? */
2592 }
2593
Eric Moore0ccdb002006-07-11 17:33:13 -06002594 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002595 if ((ret != 0) && irq_allocated) {
2596 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302597 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002598 pci_disable_msi(ioc->pcidev);
2599 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 return ret;
2601}
2602
2603/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002604/**
2605 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 * @ioc: Pointer to MPT adapter structure
2607 * @pdev: Pointer to (struct pci_dev) structure
2608 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002609 * Search for PCI bus/dev_function which matches
2610 * PCI bus/dev_function (+/-1) for newly discovered 929,
2611 * 929X, 1030 or 1035.
2612 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2614 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2615 */
2616static void
2617mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2618{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002619 struct pci_dev *peer=NULL;
2620 unsigned int slot = PCI_SLOT(pdev->devfn);
2621 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 MPT_ADAPTER *ioc_srch;
2623
Prakash, Sathya436ace72007-07-24 15:42:08 +05302624 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002625 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002626 ioc->name, pci_name(pdev), pdev->bus->number,
2627 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002628
2629 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2630 if (!peer) {
2631 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2632 if (!peer)
2633 return;
2634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635
2636 list_for_each_entry(ioc_srch, &ioc_list, list) {
2637 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002638 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 /* Paranoia checks */
2640 if (ioc->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002641 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002642 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 break;
2644 } else if (ioc_srch->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002645 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002646 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 break;
2648 }
Eric Moore29dd3602007-09-14 18:46:51 -06002649 dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002650 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 ioc_srch->alt_ioc = ioc;
2652 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 }
2654 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002655 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656}
2657
2658/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002659/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002661 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 */
2663static void
2664mpt_adapter_disable(MPT_ADAPTER *ioc)
2665{
2666 int sz;
2667 int ret;
2668
2669 if (ioc->cached_fw != NULL) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05302670 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002671 "adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302672 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2673 ioc->cached_fw, CAN_SLEEP)) < 0) {
2674 printk(MYIOC_s_WARN_FMT
2675 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002676 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 }
2678 }
2679
2680 /* Disable adapter interrupts! */
2681 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2682 ioc->active = 0;
2683 /* Clear any lingering interrupt */
2684 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2685
2686 if (ioc->alloc != NULL) {
2687 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002688 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2689 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 pci_free_consistent(ioc->pcidev, sz,
2691 ioc->alloc, ioc->alloc_dma);
2692 ioc->reply_frames = NULL;
2693 ioc->req_frames = NULL;
2694 ioc->alloc = NULL;
2695 ioc->alloc_total -= sz;
2696 }
2697
2698 if (ioc->sense_buf_pool != NULL) {
2699 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2700 pci_free_consistent(ioc->pcidev, sz,
2701 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2702 ioc->sense_buf_pool = NULL;
2703 ioc->alloc_total -= sz;
2704 }
2705
2706 if (ioc->events != NULL){
2707 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2708 kfree(ioc->events);
2709 ioc->events = NULL;
2710 ioc->alloc_total -= sz;
2711 }
2712
Prakash, Sathya984621b2008-01-11 14:42:17 +05302713 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002715 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002716 mpt_inactive_raid_list_free(ioc);
2717 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002718 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002719 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002720 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721
2722 if (ioc->spi_data.pIocPg4 != NULL) {
2723 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302724 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 ioc->spi_data.pIocPg4,
2726 ioc->spi_data.IocPg4_dma);
2727 ioc->spi_data.pIocPg4 = NULL;
2728 ioc->alloc_total -= sz;
2729 }
2730
2731 if (ioc->ReqToChain != NULL) {
2732 kfree(ioc->ReqToChain);
2733 kfree(ioc->RequestNB);
2734 ioc->ReqToChain = NULL;
2735 }
2736
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002737 kfree(ioc->ChainToChain);
2738 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002739
2740 if (ioc->HostPageBuffer != NULL) {
2741 if((ret = mpt_host_page_access_control(ioc,
2742 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002743 printk(MYIOC_s_ERR_FMT
2744 "host page buffers free failed (%d)!\n",
2745 ioc->name, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002746 }
Eric Moore29dd3602007-09-14 18:46:51 -06002747 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002748 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2749 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002750 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002751 ioc->HostPageBuffer = NULL;
2752 ioc->HostPageBuffer_sz = 0;
2753 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2754 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755}
2756
2757/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002758/**
2759 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 * @ioc: Pointer to MPT adapter structure
2761 *
2762 * This routine unregisters h/w resources and frees all alloc'd memory
2763 * associated with a MPT adapter structure.
2764 */
2765static void
2766mpt_adapter_dispose(MPT_ADAPTER *ioc)
2767{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002768 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002770 if (ioc == NULL)
2771 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002773 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002775 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002777 if (ioc->pci_irq != -1) {
2778 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302779 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002780 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002781 ioc->pci_irq = -1;
2782 }
2783
2784 if (ioc->memmap != NULL) {
2785 iounmap(ioc->memmap);
2786 ioc->memmap = NULL;
2787 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302789 pci_disable_device(ioc->pcidev);
2790 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2791
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002793 if (ioc->mtrr_reg > 0) {
2794 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002795 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002796 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797#endif
2798
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002799 /* Zap the adapter lookup ptr! */
2800 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002802 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002803 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2804 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002805
2806 if (ioc->alt_ioc)
2807 ioc->alt_ioc->alt_ioc = NULL;
2808
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002809 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810}
2811
2812/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002813/**
2814 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 * @ioc: Pointer to MPT adapter structure
2816 */
2817static void
2818MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2819{
2820 int i = 0;
2821
2822 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302823 if (ioc->prod_name)
2824 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 printk("Capabilities={");
2826
2827 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2828 printk("Initiator");
2829 i++;
2830 }
2831
2832 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2833 printk("%sTarget", i ? "," : "");
2834 i++;
2835 }
2836
2837 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2838 printk("%sLAN", i ? "," : "");
2839 i++;
2840 }
2841
2842#if 0
2843 /*
2844 * This would probably evoke more questions than it's worth
2845 */
2846 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2847 printk("%sLogBusAddr", i ? "," : "");
2848 i++;
2849 }
2850#endif
2851
2852 printk("}\n");
2853}
2854
2855/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002856/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2858 * @ioc: Pointer to MPT_ADAPTER structure
2859 * @force: Force hard KickStart of IOC
2860 * @sleepFlag: Specifies whether the process can sleep
2861 *
2862 * Returns:
2863 * 1 - DIAG reset and READY
2864 * 0 - READY initially OR soft reset and READY
2865 * -1 - Any failure on KickStart
2866 * -2 - Msg Unit Reset Failed
2867 * -3 - IO Unit Reset Failed
2868 * -4 - IOC owned by a PEER
2869 */
2870static int
2871MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2872{
2873 u32 ioc_state;
2874 int statefault = 0;
2875 int cntdn;
2876 int hard_reset_done = 0;
2877 int r;
2878 int ii;
2879 int whoinit;
2880
2881 /* Get current [raw] IOC state */
2882 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002883 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884
2885 /*
2886 * Check to see if IOC got left/stuck in doorbell handshake
2887 * grip of death. If so, hard reset the IOC.
2888 */
2889 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2890 statefault = 1;
2891 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2892 ioc->name);
2893 }
2894
2895 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002896 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 return 0;
2898
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) {
2970 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2971 ioc->name, (int)((ii+5)/HZ));
2972 return -ETIME;
2973 }
2974
2975 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002976 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 } else {
2978 mdelay (1); /* 1 msec delay */
2979 }
2980
2981 }
2982
2983 if (statefault < 3) {
2984 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2985 ioc->name,
2986 statefault==1 ? "stuck handshake" : "IOC FAULT");
2987 }
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) {
Eric Moore29dd3602007-09-14 18:46:51 -06003039 printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
3040 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 return -44;
3042 }
3043
3044 facts = &ioc->facts;
3045
3046 /* Destination (reply area)... */
3047 reply_sz = sizeof(*facts);
3048 memset(facts, 0, reply_sz);
3049
3050 /* Request area (get_facts on the stack right now!) */
3051 req_sz = sizeof(get_facts);
3052 memset(&get_facts, 0, req_sz);
3053
3054 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
3055 /* Assert: All other get_facts fields are zero! */
3056
Prakash, Sathya436ace72007-07-24 15:42:08 +05303057 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003058 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 ioc->name, req_sz, reply_sz));
3060
3061 /* No non-zero fields in the get_facts request are greater than
3062 * 1 byte in size, so we can just fire it off as is.
3063 */
3064 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3065 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3066 if (r != 0)
3067 return r;
3068
3069 /*
3070 * Now byte swap (GRRR) the necessary fields before any further
3071 * inspection of reply contents.
3072 *
3073 * But need to do some sanity checks on MsgLength (byte) field
3074 * to make sure we don't zero IOC's req_sz!
3075 */
3076 /* Did we get a valid reply? */
3077 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3078 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3079 /*
3080 * If not been here, done that, save off first WhoInit value
3081 */
3082 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3083 ioc->FirstWhoInit = facts->WhoInit;
3084 }
3085
3086 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3087 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3088 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3089 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3090 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003091 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 /* CHECKME! IOCStatus, IOCLogInfo */
3093
3094 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3095 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3096
3097 /*
3098 * FC f/w version changed between 1.1 and 1.2
3099 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3100 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3101 */
3102 if (facts->MsgVersion < 0x0102) {
3103 /*
3104 * Handle old FC f/w style, convert to new...
3105 */
3106 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3107 facts->FWVersion.Word =
3108 ((oldv<<12) & 0xFF000000) |
3109 ((oldv<<8) & 0x000FFF00);
3110 } else
3111 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3112
3113 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07003114 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3115 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3116 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 facts->CurrentHostMfaHighAddr =
3118 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3119 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3120 facts->CurrentSenseBufferHighAddr =
3121 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3122 facts->CurReplyFrameSize =
3123 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003124 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125
3126 /*
3127 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3128 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3129 * to 14 in MPI-1.01.0x.
3130 */
3131 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
3132 facts->MsgVersion > 0x0100) {
3133 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3134 }
3135
3136 sz = facts->FWImageSize;
3137 if ( sz & 0x01 )
3138 sz += 1;
3139 if ( sz & 0x02 )
3140 sz += 2;
3141 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003142
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 if (!facts->RequestFrameSize) {
3144 /* Something is wrong! */
3145 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3146 ioc->name);
3147 return -55;
3148 }
3149
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003150 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 vv = ((63 / (sz * 4)) + 1) & 0x03;
3152 ioc->NB_for_64_byte_frame = vv;
3153 while ( sz )
3154 {
3155 shiftFactor++;
3156 sz = sz >> 1;
3157 }
3158 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303159 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003160 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3161 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003162
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3164 /*
3165 * Set values for this IOC's request & reply frame sizes,
3166 * and request & reply queue depths...
3167 */
3168 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3169 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3170 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3171 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3172
Prakash, Sathya436ace72007-07-24 15:42:08 +05303173 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303175 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 ioc->name, ioc->req_sz, ioc->req_depth));
3177
3178 /* Get port facts! */
3179 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3180 return r;
3181 }
3182 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003183 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3185 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3186 RequestFrameSize)/sizeof(u32)));
3187 return -66;
3188 }
3189
3190 return 0;
3191}
3192
3193/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003194/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 * GetPortFacts - Send PortFacts request to MPT adapter.
3196 * @ioc: Pointer to MPT_ADAPTER structure
3197 * @portnum: Port number
3198 * @sleepFlag: Specifies whether the process can sleep
3199 *
3200 * Returns 0 for success, non-zero for failure.
3201 */
3202static int
3203GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3204{
3205 PortFacts_t get_pfacts;
3206 PortFactsReply_t *pfacts;
3207 int ii;
3208 int req_sz;
3209 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003210 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211
3212 /* IOC *must* NOT be in RESET state! */
3213 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003214 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3215 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216 return -4;
3217 }
3218
3219 pfacts = &ioc->pfacts[portnum];
3220
3221 /* Destination (reply area)... */
3222 reply_sz = sizeof(*pfacts);
3223 memset(pfacts, 0, reply_sz);
3224
3225 /* Request area (get_pfacts on the stack right now!) */
3226 req_sz = sizeof(get_pfacts);
3227 memset(&get_pfacts, 0, req_sz);
3228
3229 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3230 get_pfacts.PortNumber = portnum;
3231 /* Assert: All other get_pfacts fields are zero! */
3232
Prakash, Sathya436ace72007-07-24 15:42:08 +05303233 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 ioc->name, portnum));
3235
3236 /* No non-zero fields in the get_pfacts request are greater than
3237 * 1 byte in size, so we can just fire it off as is.
3238 */
3239 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3240 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3241 if (ii != 0)
3242 return ii;
3243
3244 /* Did we get a valid reply? */
3245
3246 /* Now byte swap the necessary fields in the response. */
3247 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3248 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3249 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3250 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3251 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3252 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3253 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3254 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3255 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3256
Eric Moore793955f2007-01-29 09:42:20 -07003257 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3258 pfacts->MaxDevices;
3259 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3260 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3261
3262 /*
3263 * Place all the devices on channels
3264 *
3265 * (for debuging)
3266 */
3267 if (mpt_channel_mapping) {
3268 ioc->devices_per_bus = 1;
3269 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3270 }
3271
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 return 0;
3273}
3274
3275/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003276/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 * SendIocInit - Send IOCInit request to MPT adapter.
3278 * @ioc: Pointer to MPT_ADAPTER structure
3279 * @sleepFlag: Specifies whether the process can sleep
3280 *
3281 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3282 *
3283 * Returns 0 for success, non-zero for failure.
3284 */
3285static int
3286SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3287{
3288 IOCInit_t ioc_init;
3289 MPIDefaultReply_t init_reply;
3290 u32 state;
3291 int r;
3292 int count;
3293 int cntdn;
3294
3295 memset(&ioc_init, 0, sizeof(ioc_init));
3296 memset(&init_reply, 0, sizeof(init_reply));
3297
3298 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3299 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3300
3301 /* If we are in a recovery mode and we uploaded the FW image,
3302 * then this pointer is not NULL. Skip the upload a second time.
3303 * Set this flag if cached_fw set for either IOC.
3304 */
3305 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3306 ioc->upload_fw = 1;
3307 else
3308 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303309 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3311
Eric Moore793955f2007-01-29 09:42:20 -07003312 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3313 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303314 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003315 ioc->name, ioc->facts.MsgVersion));
3316 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3317 // set MsgVersion and HeaderVersion host driver was built with
3318 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3319 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003321 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3322 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3323 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3324 return -99;
3325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3327
3328 if (sizeof(dma_addr_t) == sizeof(u64)) {
3329 /* Save the upper 32-bits of the request
3330 * (reply) and sense buffers.
3331 */
3332 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3333 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3334 } else {
3335 /* Force 32-bit addressing */
3336 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3337 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3338 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003339
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3341 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003342 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3343 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344
Prakash, Sathya436ace72007-07-24 15:42:08 +05303345 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 ioc->name, &ioc_init));
3347
3348 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3349 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003350 if (r != 0) {
3351 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003353 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354
3355 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003356 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357 */
3358
Prakash, Sathya436ace72007-07-24 15:42:08 +05303359 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003361
3362 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3363 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003365 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366
3367 /* YIKES! SUPER IMPORTANT!!!
3368 * Poll IocState until _OPERATIONAL while IOC is doing
3369 * LoopInit and TargetDiscovery!
3370 */
3371 count = 0;
3372 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3373 state = mpt_GetIocState(ioc, 1);
3374 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3375 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003376 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377 } else {
3378 mdelay(1);
3379 }
3380
3381 if (!cntdn) {
3382 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3383 ioc->name, (int)((count+5)/HZ));
3384 return -9;
3385 }
3386
3387 state = mpt_GetIocState(ioc, 1);
3388 count++;
3389 }
Eric Moore29dd3602007-09-14 18:46:51 -06003390 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 ioc->name, count));
3392
Eric Mooreba856d32006-07-11 17:34:01 -06003393 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 return r;
3395}
3396
3397/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003398/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 * SendPortEnable - Send PortEnable request to MPT adapter port.
3400 * @ioc: Pointer to MPT_ADAPTER structure
3401 * @portnum: Port number to enable
3402 * @sleepFlag: Specifies whether the process can sleep
3403 *
3404 * Send PortEnable to bring IOC to OPERATIONAL state.
3405 *
3406 * Returns 0 for success, non-zero for failure.
3407 */
3408static int
3409SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3410{
3411 PortEnable_t port_enable;
3412 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003413 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 int req_sz;
3415 int reply_sz;
3416
3417 /* Destination... */
3418 reply_sz = sizeof(MPIDefaultReply_t);
3419 memset(&reply_buf, 0, reply_sz);
3420
3421 req_sz = sizeof(PortEnable_t);
3422 memset(&port_enable, 0, req_sz);
3423
3424 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3425 port_enable.PortNumber = portnum;
3426/* port_enable.ChainOffset = 0; */
3427/* port_enable.MsgFlags = 0; */
3428/* port_enable.MsgContext = 0; */
3429
Prakash, Sathya436ace72007-07-24 15:42:08 +05303430 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 ioc->name, portnum, &port_enable));
3432
3433 /* RAID FW may take a long time to enable
3434 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003435 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003436 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3437 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3438 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003439 } else {
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 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003444 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445}
3446
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003447/**
3448 * mpt_alloc_fw_memory - allocate firmware memory
3449 * @ioc: Pointer to MPT_ADAPTER structure
3450 * @size: total FW bytes
3451 *
3452 * If memory has already been allocated, the same (cached) value
3453 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303454 *
3455 * Return 0 if successfull, or non-zero for failure
3456 **/
3457int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3459{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303460 int rc;
3461
3462 if (ioc->cached_fw) {
3463 rc = 0; /* use already allocated memory */
3464 goto out;
3465 }
3466 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3468 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303469 rc = 0;
3470 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303472 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3473 if (!ioc->cached_fw) {
3474 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3475 ioc->name);
3476 rc = -1;
3477 } else {
3478 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3479 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3480 ioc->alloc_total += size;
3481 rc = 0;
3482 }
3483 out:
3484 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303486
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003487/**
3488 * mpt_free_fw_memory - free firmware memory
3489 * @ioc: Pointer to MPT_ADAPTER structure
3490 *
3491 * If alt_img is NULL, delete from ioc structure.
3492 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303493 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494void
3495mpt_free_fw_memory(MPT_ADAPTER *ioc)
3496{
3497 int sz;
3498
Prakash, Sathya984621b2008-01-11 14:42:17 +05303499 if (!ioc->cached_fw)
3500 return;
3501
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303503 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3504 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003505 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303506 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508}
3509
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003511/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3513 * @ioc: Pointer to MPT_ADAPTER structure
3514 * @sleepFlag: Specifies whether the process can sleep
3515 *
3516 * Returns 0 for success, >0 for handshake failure
3517 * <0 for fw upload failure.
3518 *
3519 * Remark: If bound IOC and a successful FWUpload was performed
3520 * on the bound IOC, the second image is discarded
3521 * and memory is free'd. Both channels must upload to prevent
3522 * IOC from running in degraded mode.
3523 */
3524static int
3525mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3526{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 u8 reply[sizeof(FWUploadReply_t)];
3528 FWUpload_t *prequest;
3529 FWUploadReply_t *preply;
3530 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 u32 flagsLength;
3532 int ii, sz, reply_sz;
3533 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303534 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 /* If the image size is 0, we are done.
3536 */
3537 if ((sz = ioc->facts.FWImageSize) == 0)
3538 return 0;
3539
Prakash, Sathya984621b2008-01-11 14:42:17 +05303540 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3541 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542
Eric Moore29dd3602007-09-14 18:46:51 -06003543 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3544 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003545
Eric Moorebc6e0892007-09-29 10:16:28 -06003546 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3547 kzalloc(ioc->req_sz, GFP_KERNEL);
3548 if (!prequest) {
3549 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3550 "while allocating memory \n", ioc->name));
3551 mpt_free_fw_memory(ioc);
3552 return -ENOMEM;
3553 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554
Eric Moorebc6e0892007-09-29 10:16:28 -06003555 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556
3557 reply_sz = sizeof(reply);
3558 memset(preply, 0, reply_sz);
3559
3560 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3561 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3562
3563 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3564 ptcsge->DetailsLength = 12;
3565 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3566 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003567 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303570 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3571 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3572 ioc->SGE_size;
3573 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3574 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3575 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003576 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303578 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3579 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580
Eric Moore29dd3602007-09-14 18:46:51 -06003581 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582
3583 cmdStatus = -EFAULT;
3584 if (ii == 0) {
3585 /* Handshake transfer was complete and successful.
3586 * Check the Reply Frame.
3587 */
3588 int status, transfer_sz;
3589 status = le16_to_cpu(preply->IOCStatus);
3590 if (status == MPI_IOCSTATUS_SUCCESS) {
3591 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3592 if (transfer_sz == sz)
3593 cmdStatus = 0;
3594 }
3595 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303596 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 ioc->name, cmdStatus));
3598
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003599
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 if (cmdStatus) {
3601
Prakash, Sathya436ace72007-07-24 15:42:08 +05303602 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 ioc->name));
3604 mpt_free_fw_memory(ioc);
3605 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003606 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607
3608 return cmdStatus;
3609}
3610
3611/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003612/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 * mpt_downloadboot - DownloadBoot code
3614 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003615 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 * @sleepFlag: Specifies whether the process can sleep
3617 *
3618 * FwDownloadBoot requires Programmed IO access.
3619 *
3620 * Returns 0 for success
3621 * -1 FW Image size is 0
3622 * -2 No valid cached_fw Pointer
3623 * <0 for fw upload failure.
3624 */
3625static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003626mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 MpiExtImageHeader_t *pExtImage;
3629 u32 fwSize;
3630 u32 diag0val;
3631 int count;
3632 u32 *ptrFw;
3633 u32 diagRwData;
3634 u32 nextImage;
3635 u32 load_addr;
3636 u32 ioc_state=0;
3637
Prakash, Sathya436ace72007-07-24 15:42:08 +05303638 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003639 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003640
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3642 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3643 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3644 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3645 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3646 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3647
3648 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3649
3650 /* wait 1 msec */
3651 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003652 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 } else {
3654 mdelay (1);
3655 }
3656
3657 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3658 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3659
3660 for (count = 0; count < 30; count ++) {
3661 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3662 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303663 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 ioc->name, count));
3665 break;
3666 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003667 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003669 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003671 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672 }
3673 }
3674
3675 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303676 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003677 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678 ioc->name, diag0val));
3679 return -3;
3680 }
3681
3682 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3683 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3684 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3685 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3686 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3687 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3688
3689 /* Set the DiagRwEn and Disable ARM bits */
3690 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3691
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 fwSize = (pFwHeader->ImageSize + 3)/4;
3693 ptrFw = (u32 *) pFwHeader;
3694
3695 /* Write the LoadStartAddress to the DiagRw Address Register
3696 * using Programmed IO
3697 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003698 if (ioc->errata_flag_1064)
3699 pci_enable_io_access(ioc->pcidev);
3700
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303702 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 ioc->name, pFwHeader->LoadStartAddress));
3704
Prakash, Sathya436ace72007-07-24 15:42:08 +05303705 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 ioc->name, fwSize*4, ptrFw));
3707 while (fwSize--) {
3708 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3709 }
3710
3711 nextImage = pFwHeader->NextImageHeaderOffset;
3712 while (nextImage) {
3713 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3714
3715 load_addr = pExtImage->LoadStartAddress;
3716
3717 fwSize = (pExtImage->ImageSize + 3) >> 2;
3718 ptrFw = (u32 *)pExtImage;
3719
Prakash, Sathya436ace72007-07-24 15:42:08 +05303720 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 +02003721 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3723
3724 while (fwSize--) {
3725 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3726 }
3727 nextImage = pExtImage->NextImageHeaderOffset;
3728 }
3729
3730 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303731 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3733
3734 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303735 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3737
3738 /* Clear the internal flash bad bit - autoincrementing register,
3739 * so must do two writes.
3740 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003741 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003742 /*
3743 * 1030 and 1035 H/W errata, workaround to access
3744 * the ClearFlashBadSignatureBit
3745 */
3746 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3747 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3748 diagRwData |= 0x40000000;
3749 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3750 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3751
3752 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3753 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3754 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3755 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3756
3757 /* wait 1 msec */
3758 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003759 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003760 } else {
3761 mdelay (1);
3762 }
3763 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003765 if (ioc->errata_flag_1064)
3766 pci_disable_io_access(ioc->pcidev);
3767
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303769 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003770 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003772 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303773 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774 ioc->name, diag0val));
3775 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3776
3777 /* Write 0xFF to reset the sequencer */
3778 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3779
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003780 if (ioc->bus_type == SAS) {
3781 ioc_state = mpt_GetIocState(ioc, 0);
3782 if ( (GetIocFacts(ioc, sleepFlag,
3783 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303784 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003785 ioc->name, ioc_state));
3786 return -EFAULT;
3787 }
3788 }
3789
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 for (count=0; count<HZ*20; count++) {
3791 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303792 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3793 "downloadboot successful! (count=%d) IocState=%x\n",
3794 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003795 if (ioc->bus_type == SAS) {
3796 return 0;
3797 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303799 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3800 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801 ioc->name));
3802 return -EFAULT;
3803 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303804 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3805 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 ioc->name));
3807 return 0;
3808 }
3809 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003810 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811 } else {
3812 mdelay (10);
3813 }
3814 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303815 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3816 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 return -EFAULT;
3818}
3819
3820/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003821/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822 * KickStart - Perform hard reset of MPT adapter.
3823 * @ioc: Pointer to MPT_ADAPTER structure
3824 * @force: Force hard reset
3825 * @sleepFlag: Specifies whether the process can sleep
3826 *
3827 * This routine places MPT adapter in diagnostic mode via the
3828 * WriteSequence register, and then performs a hard reset of adapter
3829 * via the Diagnostic register.
3830 *
3831 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3832 * or NO_SLEEP (interrupt thread, use mdelay)
3833 * force - 1 if doorbell active, board fault state
3834 * board operational, IOC_RECOVERY or
3835 * IOC_BRINGUP and there is an alt_ioc.
3836 * 0 else
3837 *
3838 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003839 * 1 - hard reset, READY
3840 * 0 - no reset due to History bit, READY
3841 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842 * OR reset but failed to come READY
3843 * -2 - no reset, could not enter DIAG mode
3844 * -3 - reset but bad FW bit
3845 */
3846static int
3847KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3848{
3849 int hard_reset_done = 0;
3850 u32 ioc_state=0;
3851 int cnt,cntdn;
3852
Eric Moore29dd3602007-09-14 18:46:51 -06003853 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003854 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855 /* Always issue a Msg Unit Reset first. This will clear some
3856 * SCSI bus hang conditions.
3857 */
3858 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3859
3860 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003861 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862 } else {
3863 mdelay (1000);
3864 }
3865 }
3866
3867 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3868 if (hard_reset_done < 0)
3869 return hard_reset_done;
3870
Prakash, Sathya436ace72007-07-24 15:42:08 +05303871 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003872 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873
3874 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3875 for (cnt=0; cnt<cntdn; cnt++) {
3876 ioc_state = mpt_GetIocState(ioc, 1);
3877 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303878 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 ioc->name, cnt));
3880 return hard_reset_done;
3881 }
3882 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003883 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 } else {
3885 mdelay (10);
3886 }
3887 }
3888
Eric Moore29dd3602007-09-14 18:46:51 -06003889 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3890 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891 return -1;
3892}
3893
3894/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003895/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896 * mpt_diag_reset - Perform hard reset of the adapter.
3897 * @ioc: Pointer to MPT_ADAPTER structure
3898 * @ignore: Set if to honor and clear to ignore
3899 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003900 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 * else set to NO_SLEEP (use mdelay instead)
3902 *
3903 * This routine places the adapter in diagnostic mode via the
3904 * WriteSequence register and then performs a hard reset of adapter
3905 * via the Diagnostic register. Adapter should be in ready state
3906 * upon successful completion.
3907 *
3908 * Returns: 1 hard reset successful
3909 * 0 no reset performed because reset history bit set
3910 * -2 enabling diagnostic mode failed
3911 * -3 diagnostic reset failed
3912 */
3913static int
3914mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3915{
3916 u32 diag0val;
3917 u32 doorbell;
3918 int hard_reset_done = 0;
3919 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303921 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922
Eric Moorecd2c6192007-01-29 09:47:47 -07003923 /* Clear any existing interrupts */
3924 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3925
Eric Moore87cf8982006-06-27 16:09:26 -06003926 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303927 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003928 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003929 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3930 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3931 if (sleepFlag == CAN_SLEEP)
3932 msleep(1);
3933 else
3934 mdelay(1);
3935
3936 for (count = 0; count < 60; count ++) {
3937 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3938 doorbell &= MPI_IOC_STATE_MASK;
3939
Prakash, Sathya436ace72007-07-24 15:42:08 +05303940 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003941 "looking for READY STATE: doorbell=%x"
3942 " count=%d\n",
3943 ioc->name, doorbell, count));
3944 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003945 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003946 }
3947
3948 /* wait 1 sec */
3949 if (sleepFlag == CAN_SLEEP)
3950 msleep(1000);
3951 else
3952 mdelay(1000);
3953 }
3954 return -1;
3955 }
3956
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 /* Use "Diagnostic reset" method! (only thing available!) */
3958 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3959
Prakash, Sathya436ace72007-07-24 15:42:08 +05303960 if (ioc->debug_level & MPT_DEBUG) {
3961 if (ioc->alt_ioc)
3962 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3963 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303965 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966
3967 /* Do the reset if we are told to ignore the reset history
3968 * or if the reset history is 0
3969 */
3970 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3971 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3972 /* Write magic sequence to WriteSequence register
3973 * Loop until in diagnostic mode
3974 */
3975 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3976 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3977 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3978 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3979 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3980 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3981
3982 /* wait 100 msec */
3983 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003984 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985 } else {
3986 mdelay (100);
3987 }
3988
3989 count++;
3990 if (count > 20) {
3991 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3992 ioc->name, diag0val);
3993 return -2;
3994
3995 }
3996
3997 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3998
Prakash, Sathya436ace72007-07-24 15:42:08 +05303999 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 ioc->name, diag0val));
4001 }
4002
Prakash, Sathya436ace72007-07-24 15:42:08 +05304003 if (ioc->debug_level & MPT_DEBUG) {
4004 if (ioc->alt_ioc)
4005 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4006 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304008 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 /*
4010 * Disable the ARM (Bug fix)
4011 *
4012 */
4013 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004014 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015
4016 /*
4017 * Now hit the reset bit in the Diagnostic register
4018 * (THE BIG HAMMER!) (Clears DRWE bit).
4019 */
4020 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
4021 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304022 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 ioc->name));
4024
4025 /*
4026 * Call each currently registered protocol IOC reset handler
4027 * with pre-reset indication.
4028 * NOTE: If we're doing _IOC_BRINGUP, there can be no
4029 * MptResetHandlers[] registered yet.
4030 */
4031 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304032 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 int r = 0;
4034
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304035 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
4036 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304037 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4038 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304039 ioc->name, cb_idx));
4040 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304042 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4043 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05304044 ioc->name, ioc->alt_ioc->name, cb_idx));
4045 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 }
4047 }
4048 }
4049 /* FIXME? Examine results here? */
4050 }
4051
Eric Moore0ccdb002006-07-11 17:33:13 -06004052 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304053 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06004054 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304055 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4056 else
4057 cached_fw = NULL;
4058 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059 /* If the DownloadBoot operation fails, the
4060 * IOC will be left unusable. This is a fatal error
4061 * case. _diag_reset will return < 0
4062 */
4063 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304064 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4066 break;
4067 }
4068
Prakash, Sathya436ace72007-07-24 15:42:08 +05304069 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304070 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071 /* wait 1 sec */
4072 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004073 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074 } else {
4075 mdelay (1000);
4076 }
4077 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304078 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004079 printk(MYIOC_s_WARN_FMT
4080 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081 }
4082
4083 } else {
4084 /* Wait for FW to reload and for board
4085 * to go to the READY state.
4086 * Maximum wait is 60 seconds.
4087 * If fail, no error will check again
4088 * with calling program.
4089 */
4090 for (count = 0; count < 60; count ++) {
4091 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4092 doorbell &= MPI_IOC_STATE_MASK;
4093
4094 if (doorbell == MPI_IOC_STATE_READY) {
4095 break;
4096 }
4097
4098 /* wait 1 sec */
4099 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004100 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101 } else {
4102 mdelay (1000);
4103 }
4104 }
4105 }
4106 }
4107
4108 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304109 if (ioc->debug_level & MPT_DEBUG) {
4110 if (ioc->alt_ioc)
4111 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4112 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4113 ioc->name, diag0val, diag1val));
4114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115
4116 /* Clear RESET_HISTORY bit! Place board in the
4117 * diagnostic mode to update the diag register.
4118 */
4119 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4120 count = 0;
4121 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4122 /* Write magic sequence to WriteSequence register
4123 * Loop until in diagnostic mode
4124 */
4125 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4126 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4127 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4128 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4129 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4130 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4131
4132 /* wait 100 msec */
4133 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004134 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135 } else {
4136 mdelay (100);
4137 }
4138
4139 count++;
4140 if (count > 20) {
4141 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4142 ioc->name, diag0val);
4143 break;
4144 }
4145 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4146 }
4147 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4148 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4149 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4150 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4151 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4152 ioc->name);
4153 }
4154
4155 /* Disable Diagnostic Mode
4156 */
4157 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4158
4159 /* Check FW reload status flags.
4160 */
4161 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4162 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4163 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4164 ioc->name, diag0val);
4165 return -3;
4166 }
4167
Prakash, Sathya436ace72007-07-24 15:42:08 +05304168 if (ioc->debug_level & MPT_DEBUG) {
4169 if (ioc->alt_ioc)
4170 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4171 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304173 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174
4175 /*
4176 * Reset flag that says we've enabled event notification
4177 */
4178 ioc->facts.EventState = 0;
4179
4180 if (ioc->alt_ioc)
4181 ioc->alt_ioc->facts.EventState = 0;
4182
4183 return hard_reset_done;
4184}
4185
4186/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004187/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 * SendIocReset - Send IOCReset request to MPT adapter.
4189 * @ioc: Pointer to MPT_ADAPTER structure
4190 * @reset_type: reset type, expected values are
4191 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004192 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193 *
4194 * Send IOCReset request to the MPT adapter.
4195 *
4196 * Returns 0 for success, non-zero for failure.
4197 */
4198static int
4199SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4200{
4201 int r;
4202 u32 state;
4203 int cntdn, count;
4204
Prakash, Sathya436ace72007-07-24 15:42:08 +05304205 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 ioc->name, reset_type));
4207 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4208 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4209 return r;
4210
4211 /* FW ACK'd request, wait for READY state
4212 */
4213 count = 0;
4214 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4215
4216 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4217 cntdn--;
4218 count++;
4219 if (!cntdn) {
4220 if (sleepFlag != CAN_SLEEP)
4221 count *= 10;
4222
Eric Moore29dd3602007-09-14 18:46:51 -06004223 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
4224 ioc->name, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225 return -ETIME;
4226 }
4227
4228 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004229 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230 } else {
4231 mdelay (1); /* 1 msec delay */
4232 }
4233 }
4234
4235 /* TODO!
4236 * Cleanup all event stuff for this IOC; re-issue EventNotification
4237 * request if needed.
4238 */
4239 if (ioc->facts.Function)
4240 ioc->facts.EventState = 0;
4241
4242 return 0;
4243}
4244
4245/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004246/**
4247 * initChainBuffers - Allocate memory for and initialize chain buffers
4248 * @ioc: Pointer to MPT_ADAPTER structure
4249 *
4250 * Allocates memory for and initializes chain buffers,
4251 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 */
4253static int
4254initChainBuffers(MPT_ADAPTER *ioc)
4255{
4256 u8 *mem;
4257 int sz, ii, num_chain;
4258 int scale, num_sge, numSGE;
4259
4260 /* ReqToChain size must equal the req_depth
4261 * index = req_idx
4262 */
4263 if (ioc->ReqToChain == NULL) {
4264 sz = ioc->req_depth * sizeof(int);
4265 mem = kmalloc(sz, GFP_ATOMIC);
4266 if (mem == NULL)
4267 return -1;
4268
4269 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304270 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271 ioc->name, mem, sz));
4272 mem = kmalloc(sz, GFP_ATOMIC);
4273 if (mem == NULL)
4274 return -1;
4275
4276 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304277 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278 ioc->name, mem, sz));
4279 }
4280 for (ii = 0; ii < ioc->req_depth; ii++) {
4281 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4282 }
4283
4284 /* ChainToChain size must equal the total number
4285 * of chain buffers to be allocated.
4286 * index = chain_idx
4287 *
4288 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004289 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290 *
4291 * num_sge = num sge in request frame + last chain buffer
4292 * scale = num sge per chain buffer if no chain element
4293 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304294 scale = ioc->req_sz / ioc->SGE_size;
4295 if (ioc->sg_addr_size == sizeof(u64))
4296 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304298 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304300 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304302 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304304 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4305 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304307 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 ioc->name, num_sge, numSGE));
4309
4310 if ( numSGE > MPT_SCSI_SG_DEPTH )
4311 numSGE = MPT_SCSI_SG_DEPTH;
4312
4313 num_chain = 1;
4314 while (numSGE - num_sge > 0) {
4315 num_chain++;
4316 num_sge += (scale - 1);
4317 }
4318 num_chain++;
4319
Prakash, Sathya436ace72007-07-24 15:42:08 +05304320 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321 ioc->name, numSGE, num_sge, num_chain));
4322
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004323 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324 num_chain *= MPT_SCSI_CAN_QUEUE;
4325 else
4326 num_chain *= MPT_FC_CAN_QUEUE;
4327
4328 ioc->num_chain = num_chain;
4329
4330 sz = num_chain * sizeof(int);
4331 if (ioc->ChainToChain == NULL) {
4332 mem = kmalloc(sz, GFP_ATOMIC);
4333 if (mem == NULL)
4334 return -1;
4335
4336 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304337 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 ioc->name, mem, sz));
4339 } else {
4340 mem = (u8 *) ioc->ChainToChain;
4341 }
4342 memset(mem, 0xFF, sz);
4343 return num_chain;
4344}
4345
4346/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004347/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4349 * @ioc: Pointer to MPT_ADAPTER structure
4350 *
4351 * This routine allocates memory for the MPT reply and request frame
4352 * pools (if necessary), and primes the IOC reply FIFO with
4353 * reply frames.
4354 *
4355 * Returns 0 for success, non-zero for failure.
4356 */
4357static int
4358PrimeIocFifos(MPT_ADAPTER *ioc)
4359{
4360 MPT_FRAME_HDR *mf;
4361 unsigned long flags;
4362 dma_addr_t alloc_dma;
4363 u8 *mem;
4364 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304365 u64 dma_mask;
4366
4367 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368
4369 /* Prime reply FIFO... */
4370
4371 if (ioc->reply_frames == NULL) {
4372 if ( (num_chain = initChainBuffers(ioc)) < 0)
4373 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304374 /*
4375 * 1078 errata workaround for the 36GB limitation
4376 */
4377 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
4378 ioc->dma_mask > DMA_35BIT_MASK) {
4379 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4380 && !pci_set_consistent_dma_mask(ioc->pcidev,
4381 DMA_BIT_MASK(32))) {
4382 dma_mask = DMA_35BIT_MASK;
4383 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4384 "setting 35 bit addressing for "
4385 "Request/Reply/Chain and Sense Buffers\n",
4386 ioc->name));
4387 } else {
4388 /*Reseting DMA mask to 64 bit*/
4389 pci_set_dma_mask(ioc->pcidev,
4390 DMA_BIT_MASK(64));
4391 pci_set_consistent_dma_mask(ioc->pcidev,
4392 DMA_BIT_MASK(64));
4393
4394 printk(MYIOC_s_ERR_FMT
4395 "failed setting 35 bit addressing for "
4396 "Request/Reply/Chain and Sense Buffers\n",
4397 ioc->name);
4398 return -1;
4399 }
4400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401
4402 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304403 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304405 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406 ioc->name, reply_sz, reply_sz));
4407
4408 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304409 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304411 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 ioc->name, sz, sz));
4413 total_size += sz;
4414
4415 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304416 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304418 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 ioc->name, sz, sz, num_chain));
4420
4421 total_size += sz;
4422 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4423 if (mem == NULL) {
4424 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4425 ioc->name);
4426 goto out_fail;
4427 }
4428
Prakash, Sathya436ace72007-07-24 15:42:08 +05304429 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4431
4432 memset(mem, 0, total_size);
4433 ioc->alloc_total += total_size;
4434 ioc->alloc = mem;
4435 ioc->alloc_dma = alloc_dma;
4436 ioc->alloc_sz = total_size;
4437 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4438 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4439
Prakash, Sathya436ace72007-07-24 15:42:08 +05304440 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004441 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4442
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 alloc_dma += reply_sz;
4444 mem += reply_sz;
4445
4446 /* Request FIFO - WE manage this! */
4447
4448 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4449 ioc->req_frames_dma = alloc_dma;
4450
Prakash, Sathya436ace72007-07-24 15:42:08 +05304451 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452 ioc->name, mem, (void *)(ulong)alloc_dma));
4453
4454 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4455
4456#if defined(CONFIG_MTRR) && 0
4457 /*
4458 * Enable Write Combining MTRR for IOC's memory region.
4459 * (at least as much as we can; "size and base must be
4460 * multiples of 4 kiB"
4461 */
4462 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4463 sz,
4464 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304465 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 ioc->name, ioc->req_frames_dma, sz));
4467#endif
4468
4469 for (i = 0; i < ioc->req_depth; i++) {
4470 alloc_dma += ioc->req_sz;
4471 mem += ioc->req_sz;
4472 }
4473
4474 ioc->ChainBuffer = mem;
4475 ioc->ChainBufferDMA = alloc_dma;
4476
Prakash, Sathya436ace72007-07-24 15:42:08 +05304477 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4479
4480 /* Initialize the free chain Q.
4481 */
4482
4483 INIT_LIST_HEAD(&ioc->FreeChainQ);
4484
4485 /* Post the chain buffers to the FreeChainQ.
4486 */
4487 mem = (u8 *)ioc->ChainBuffer;
4488 for (i=0; i < num_chain; i++) {
4489 mf = (MPT_FRAME_HDR *) mem;
4490 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4491 mem += ioc->req_sz;
4492 }
4493
4494 /* Initialize Request frames linked list
4495 */
4496 alloc_dma = ioc->req_frames_dma;
4497 mem = (u8 *) ioc->req_frames;
4498
4499 spin_lock_irqsave(&ioc->FreeQlock, flags);
4500 INIT_LIST_HEAD(&ioc->FreeQ);
4501 for (i = 0; i < ioc->req_depth; i++) {
4502 mf = (MPT_FRAME_HDR *) mem;
4503
4504 /* Queue REQUESTs *internally*! */
4505 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4506
4507 mem += ioc->req_sz;
4508 }
4509 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4510
4511 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4512 ioc->sense_buf_pool =
4513 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4514 if (ioc->sense_buf_pool == NULL) {
4515 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4516 ioc->name);
4517 goto out_fail;
4518 }
4519
4520 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4521 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304522 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004523 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4524
4525 }
4526
4527 /* Post Reply frames to FIFO
4528 */
4529 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304530 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4532
4533 for (i = 0; i < ioc->reply_depth; i++) {
4534 /* Write each address to the IOC! */
4535 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4536 alloc_dma += ioc->reply_sz;
4537 }
4538
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304539 if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
4540 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4541 ioc->dma_mask))
4542 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4543 "restoring 64 bit addressing\n", ioc->name));
4544
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545 return 0;
4546
4547out_fail:
4548 if (ioc->alloc != NULL) {
4549 sz = ioc->alloc_sz;
4550 pci_free_consistent(ioc->pcidev,
4551 sz,
4552 ioc->alloc, ioc->alloc_dma);
4553 ioc->reply_frames = NULL;
4554 ioc->req_frames = NULL;
4555 ioc->alloc_total -= sz;
4556 }
4557 if (ioc->sense_buf_pool != NULL) {
4558 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4559 pci_free_consistent(ioc->pcidev,
4560 sz,
4561 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4562 ioc->sense_buf_pool = NULL;
4563 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304564
4565 if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
4566 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4567 DMA_BIT_MASK(64)))
4568 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4569 "restoring 64 bit addressing\n", ioc->name));
4570
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 return -1;
4572}
4573
4574/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4575/**
4576 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4577 * from IOC via doorbell handshake method.
4578 * @ioc: Pointer to MPT_ADAPTER structure
4579 * @reqBytes: Size of the request in bytes
4580 * @req: Pointer to MPT request frame
4581 * @replyBytes: Expected size of the reply in bytes
4582 * @u16reply: Pointer to area where reply should be written
4583 * @maxwait: Max wait time for a reply (in seconds)
4584 * @sleepFlag: Specifies whether the process can sleep
4585 *
4586 * NOTES: It is the callers responsibility to byte-swap fields in the
4587 * request which are greater than 1 byte in size. It is also the
4588 * callers responsibility to byte-swap response fields which are
4589 * greater than 1 byte in size.
4590 *
4591 * Returns 0 for success, non-zero for failure.
4592 */
4593static int
4594mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004595 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596{
4597 MPIDefaultReply_t *mptReply;
4598 int failcnt = 0;
4599 int t;
4600
4601 /*
4602 * Get ready to cache a handshake reply
4603 */
4604 ioc->hs_reply_idx = 0;
4605 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4606 mptReply->MsgLength = 0;
4607
4608 /*
4609 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4610 * then tell IOC that we want to handshake a request of N words.
4611 * (WRITE u32val to Doorbell reg).
4612 */
4613 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4614 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4615 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4616 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4617
4618 /*
4619 * Wait for IOC's doorbell handshake int
4620 */
4621 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4622 failcnt++;
4623
Prakash, Sathya436ace72007-07-24 15:42:08 +05304624 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4626
4627 /* Read doorbell and check for active bit */
4628 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4629 return -1;
4630
4631 /*
4632 * Clear doorbell int (WRITE 0 to IntStatus reg),
4633 * then wait for IOC to ACKnowledge that it's ready for
4634 * our handshake request.
4635 */
4636 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4637 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4638 failcnt++;
4639
4640 if (!failcnt) {
4641 int ii;
4642 u8 *req_as_bytes = (u8 *) req;
4643
4644 /*
4645 * Stuff request words via doorbell handshake,
4646 * with ACK from IOC for each.
4647 */
4648 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4649 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4650 (req_as_bytes[(ii*4) + 1] << 8) |
4651 (req_as_bytes[(ii*4) + 2] << 16) |
4652 (req_as_bytes[(ii*4) + 3] << 24));
4653
4654 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4655 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4656 failcnt++;
4657 }
4658
Prakash, Sathya436ace72007-07-24 15:42:08 +05304659 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004660 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661
Prakash, Sathya436ace72007-07-24 15:42:08 +05304662 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4664
4665 /*
4666 * Wait for completion of doorbell handshake reply from the IOC
4667 */
4668 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4669 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004670
Prakash, Sathya436ace72007-07-24 15:42:08 +05304671 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4673
4674 /*
4675 * Copy out the cached reply...
4676 */
4677 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4678 u16reply[ii] = ioc->hs_reply[ii];
4679 } else {
4680 return -99;
4681 }
4682
4683 return -failcnt;
4684}
4685
4686/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004687/**
4688 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004689 * @ioc: Pointer to MPT_ADAPTER structure
4690 * @howlong: How long to wait (in seconds)
4691 * @sleepFlag: Specifies whether the process can sleep
4692 *
4693 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004694 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4695 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004696 *
4697 * Returns a negative value on failure, else wait loop count.
4698 */
4699static int
4700WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4701{
4702 int cntdn;
4703 int count = 0;
4704 u32 intstat=0;
4705
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004706 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707
4708 if (sleepFlag == CAN_SLEEP) {
4709 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004710 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4712 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4713 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714 count++;
4715 }
4716 } else {
4717 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004718 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4720 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4721 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722 count++;
4723 }
4724 }
4725
4726 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304727 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728 ioc->name, count));
4729 return count;
4730 }
4731
4732 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4733 ioc->name, count, intstat);
4734 return -1;
4735}
4736
4737/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004738/**
4739 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740 * @ioc: Pointer to MPT_ADAPTER structure
4741 * @howlong: How long to wait (in seconds)
4742 * @sleepFlag: Specifies whether the process can sleep
4743 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004744 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4745 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746 *
4747 * Returns a negative value on failure, else wait loop count.
4748 */
4749static int
4750WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4751{
4752 int cntdn;
4753 int count = 0;
4754 u32 intstat=0;
4755
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004756 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 if (sleepFlag == CAN_SLEEP) {
4758 while (--cntdn) {
4759 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4760 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4761 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004762 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 count++;
4764 }
4765 } else {
4766 while (--cntdn) {
4767 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4768 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4769 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004770 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 count++;
4772 }
4773 }
4774
4775 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304776 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777 ioc->name, count, howlong));
4778 return count;
4779 }
4780
4781 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4782 ioc->name, count, intstat);
4783 return -1;
4784}
4785
4786/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004787/**
4788 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 * @ioc: Pointer to MPT_ADAPTER structure
4790 * @howlong: How long to wait (in seconds)
4791 * @sleepFlag: Specifies whether the process can sleep
4792 *
4793 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4794 * Reply is cached to IOC private area large enough to hold a maximum
4795 * of 128 bytes of reply data.
4796 *
4797 * Returns a negative value on failure, else size of reply in WORDS.
4798 */
4799static int
4800WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4801{
4802 int u16cnt = 0;
4803 int failcnt = 0;
4804 int t;
4805 u16 *hs_reply = ioc->hs_reply;
4806 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4807 u16 hword;
4808
4809 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4810
4811 /*
4812 * Get first two u16's so we can look at IOC's intended reply MsgLength
4813 */
4814 u16cnt=0;
4815 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4816 failcnt++;
4817 } else {
4818 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4819 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4820 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4821 failcnt++;
4822 else {
4823 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4824 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4825 }
4826 }
4827
Prakash, Sathya436ace72007-07-24 15:42:08 +05304828 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004829 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4831
4832 /*
4833 * If no error (and IOC said MsgLength is > 0), piece together
4834 * reply 16 bits at a time.
4835 */
4836 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4837 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4838 failcnt++;
4839 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4840 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004841 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842 hs_reply[u16cnt] = hword;
4843 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4844 }
4845
4846 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4847 failcnt++;
4848 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4849
4850 if (failcnt) {
4851 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4852 ioc->name);
4853 return -failcnt;
4854 }
4855#if 0
4856 else if (u16cnt != (2 * mptReply->MsgLength)) {
4857 return -101;
4858 }
4859 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4860 return -102;
4861 }
4862#endif
4863
Prakash, Sathya436ace72007-07-24 15:42:08 +05304864 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004865 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866
Prakash, Sathya436ace72007-07-24 15:42:08 +05304867 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868 ioc->name, t, u16cnt/2));
4869 return u16cnt/2;
4870}
4871
4872/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004873/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874 * GetLanConfigPages - Fetch LANConfig pages.
4875 * @ioc: Pointer to MPT_ADAPTER structure
4876 *
4877 * Return: 0 for success
4878 * -ENOMEM if no memory available
4879 * -EPERM if not allowed due to ISR context
4880 * -EAGAIN if no msg frames currently available
4881 * -EFAULT for non-successful reply or no reply (timeout)
4882 */
4883static int
4884GetLanConfigPages(MPT_ADAPTER *ioc)
4885{
4886 ConfigPageHeader_t hdr;
4887 CONFIGPARMS cfg;
4888 LANPage0_t *ppage0_alloc;
4889 dma_addr_t page0_dma;
4890 LANPage1_t *ppage1_alloc;
4891 dma_addr_t page1_dma;
4892 int rc = 0;
4893 int data_sz;
4894 int copy_sz;
4895
4896 /* Get LAN Page 0 header */
4897 hdr.PageVersion = 0;
4898 hdr.PageLength = 0;
4899 hdr.PageNumber = 0;
4900 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004901 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902 cfg.physAddr = -1;
4903 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4904 cfg.dir = 0;
4905 cfg.pageAddr = 0;
4906 cfg.timeout = 0;
4907
4908 if ((rc = mpt_config(ioc, &cfg)) != 0)
4909 return rc;
4910
4911 if (hdr.PageLength > 0) {
4912 data_sz = hdr.PageLength * 4;
4913 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4914 rc = -ENOMEM;
4915 if (ppage0_alloc) {
4916 memset((u8 *)ppage0_alloc, 0, data_sz);
4917 cfg.physAddr = page0_dma;
4918 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4919
4920 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4921 /* save the data */
4922 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4923 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4924
4925 }
4926
4927 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4928
4929 /* FIXME!
4930 * Normalize endianness of structure data,
4931 * by byte-swapping all > 1 byte fields!
4932 */
4933
4934 }
4935
4936 if (rc)
4937 return rc;
4938 }
4939
4940 /* Get LAN Page 1 header */
4941 hdr.PageVersion = 0;
4942 hdr.PageLength = 0;
4943 hdr.PageNumber = 1;
4944 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004945 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946 cfg.physAddr = -1;
4947 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4948 cfg.dir = 0;
4949 cfg.pageAddr = 0;
4950
4951 if ((rc = mpt_config(ioc, &cfg)) != 0)
4952 return rc;
4953
4954 if (hdr.PageLength == 0)
4955 return 0;
4956
4957 data_sz = hdr.PageLength * 4;
4958 rc = -ENOMEM;
4959 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4960 if (ppage1_alloc) {
4961 memset((u8 *)ppage1_alloc, 0, data_sz);
4962 cfg.physAddr = page1_dma;
4963 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4964
4965 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4966 /* save the data */
4967 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4968 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4969 }
4970
4971 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4972
4973 /* FIXME!
4974 * Normalize endianness of structure data,
4975 * by byte-swapping all > 1 byte fields!
4976 */
4977
4978 }
4979
4980 return rc;
4981}
4982
4983/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004984/**
4985 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004986 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004987 * @persist_opcode: see below
4988 *
4989 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4990 * devices not currently present.
4991 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4992 *
4993 * NOTE: Don't use not this function during interrupt time.
4994 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004995 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004996 */
4997
4998/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4999int
5000mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
5001{
5002 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
5003 SasIoUnitControlReply_t *sasIoUnitCntrReply;
5004 MPT_FRAME_HDR *mf = NULL;
5005 MPIHeader_t *mpi_hdr;
5006
5007
5008 /* insure garbage is not sent to fw */
5009 switch(persist_opcode) {
5010
5011 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
5012 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
5013 break;
5014
5015 default:
5016 return -1;
5017 break;
5018 }
5019
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07005020 printk("%s: persist_opcode=%x\n",__func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005021
5022 /* Get a MF for this command.
5023 */
5024 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07005025 printk("%s: no msg frames!\n",__func__);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005026 return -1;
5027 }
5028
5029 mpi_hdr = (MPIHeader_t *) mf;
5030 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
5031 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
5032 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
5033 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
5034 sasIoUnitCntrReq->Operation = persist_opcode;
5035
5036 init_timer(&ioc->persist_timer);
5037 ioc->persist_timer.data = (unsigned long) ioc;
5038 ioc->persist_timer.function = mpt_timer_expired;
5039 ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */;
5040 ioc->persist_wait_done=0;
5041 add_timer(&ioc->persist_timer);
5042 mpt_put_msg_frame(mpt_base_index, ioc, mf);
5043 wait_event(mpt_waitq, ioc->persist_wait_done);
5044
5045 sasIoUnitCntrReply =
5046 (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
5047 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5048 printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07005049 __func__,
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005050 sasIoUnitCntrReply->IOCStatus,
5051 sasIoUnitCntrReply->IOCLogInfo);
5052 return -1;
5053 }
5054
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07005055 printk("%s: success\n",__func__);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005056 return 0;
5057}
5058
5059/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005060
5061static void
5062mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5063 MpiEventDataRaid_t * pRaidEventData)
5064{
5065 int volume;
5066 int reason;
5067 int disk;
5068 int status;
5069 int flags;
5070 int state;
5071
5072 volume = pRaidEventData->VolumeID;
5073 reason = pRaidEventData->ReasonCode;
5074 disk = pRaidEventData->PhysDiskNum;
5075 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5076 flags = (status >> 0) & 0xff;
5077 state = (status >> 8) & 0xff;
5078
5079 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5080 return;
5081 }
5082
5083 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5084 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5085 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005086 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5087 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005088 } else {
5089 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5090 ioc->name, volume);
5091 }
5092
5093 switch(reason) {
5094 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5095 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5096 ioc->name);
5097 break;
5098
5099 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5100
5101 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5102 ioc->name);
5103 break;
5104
5105 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5106 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5107 ioc->name);
5108 break;
5109
5110 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5111 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5112 ioc->name,
5113 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5114 ? "optimal"
5115 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5116 ? "degraded"
5117 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5118 ? "failed"
5119 : "state unknown",
5120 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5121 ? ", enabled" : "",
5122 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5123 ? ", quiesced" : "",
5124 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5125 ? ", resync in progress" : "" );
5126 break;
5127
5128 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5129 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5130 ioc->name, disk);
5131 break;
5132
5133 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5134 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5135 ioc->name);
5136 break;
5137
5138 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5139 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5140 ioc->name);
5141 break;
5142
5143 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5144 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5145 ioc->name);
5146 break;
5147
5148 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5149 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5150 ioc->name,
5151 state == MPI_PHYSDISK0_STATUS_ONLINE
5152 ? "online"
5153 : state == MPI_PHYSDISK0_STATUS_MISSING
5154 ? "missing"
5155 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5156 ? "not compatible"
5157 : state == MPI_PHYSDISK0_STATUS_FAILED
5158 ? "failed"
5159 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5160 ? "initializing"
5161 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5162 ? "offline requested"
5163 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5164 ? "failed requested"
5165 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5166 ? "offline"
5167 : "state unknown",
5168 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5169 ? ", out of sync" : "",
5170 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5171 ? ", quiesced" : "" );
5172 break;
5173
5174 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5175 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5176 ioc->name, disk);
5177 break;
5178
5179 case MPI_EVENT_RAID_RC_SMART_DATA:
5180 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5181 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5182 break;
5183
5184 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5185 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5186 ioc->name, disk);
5187 break;
5188 }
5189}
5190
5191/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005192/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5194 * @ioc: Pointer to MPT_ADAPTER structure
5195 *
5196 * Returns: 0 for success
5197 * -ENOMEM if no memory available
5198 * -EPERM if not allowed due to ISR context
5199 * -EAGAIN if no msg frames currently available
5200 * -EFAULT for non-successful reply or no reply (timeout)
5201 */
5202static int
5203GetIoUnitPage2(MPT_ADAPTER *ioc)
5204{
5205 ConfigPageHeader_t hdr;
5206 CONFIGPARMS cfg;
5207 IOUnitPage2_t *ppage_alloc;
5208 dma_addr_t page_dma;
5209 int data_sz;
5210 int rc;
5211
5212 /* Get the page header */
5213 hdr.PageVersion = 0;
5214 hdr.PageLength = 0;
5215 hdr.PageNumber = 2;
5216 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005217 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218 cfg.physAddr = -1;
5219 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5220 cfg.dir = 0;
5221 cfg.pageAddr = 0;
5222 cfg.timeout = 0;
5223
5224 if ((rc = mpt_config(ioc, &cfg)) != 0)
5225 return rc;
5226
5227 if (hdr.PageLength == 0)
5228 return 0;
5229
5230 /* Read the config page */
5231 data_sz = hdr.PageLength * 4;
5232 rc = -ENOMEM;
5233 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5234 if (ppage_alloc) {
5235 memset((u8 *)ppage_alloc, 0, data_sz);
5236 cfg.physAddr = page_dma;
5237 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5238
5239 /* If Good, save data */
5240 if ((rc = mpt_config(ioc, &cfg)) == 0)
5241 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5242
5243 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5244 }
5245
5246 return rc;
5247}
5248
5249/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005250/**
5251 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252 * @ioc: Pointer to a Adapter Strucutre
5253 * @portnum: IOC port number
5254 *
5255 * Return: -EFAULT if read of config page header fails
5256 * or if no nvram
5257 * If read of SCSI Port Page 0 fails,
5258 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5259 * Adapter settings: async, narrow
5260 * Return 1
5261 * If read of SCSI Port Page 2 fails,
5262 * Adapter settings valid
5263 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5264 * Return 1
5265 * Else
5266 * Both valid
5267 * Return 0
5268 * CHECK - what type of locking mechanisms should be used????
5269 */
5270static int
5271mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5272{
5273 u8 *pbuf;
5274 dma_addr_t buf_dma;
5275 CONFIGPARMS cfg;
5276 ConfigPageHeader_t header;
5277 int ii;
5278 int data, rc = 0;
5279
5280 /* Allocate memory
5281 */
5282 if (!ioc->spi_data.nvram) {
5283 int sz;
5284 u8 *mem;
5285 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5286 mem = kmalloc(sz, GFP_ATOMIC);
5287 if (mem == NULL)
5288 return -EFAULT;
5289
5290 ioc->spi_data.nvram = (int *) mem;
5291
Prakash, Sathya436ace72007-07-24 15:42:08 +05305292 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293 ioc->name, ioc->spi_data.nvram, sz));
5294 }
5295
5296 /* Invalidate NVRAM information
5297 */
5298 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5299 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5300 }
5301
5302 /* Read SPP0 header, allocate memory, then read page.
5303 */
5304 header.PageVersion = 0;
5305 header.PageLength = 0;
5306 header.PageNumber = 0;
5307 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005308 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309 cfg.physAddr = -1;
5310 cfg.pageAddr = portnum;
5311 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5312 cfg.dir = 0;
5313 cfg.timeout = 0; /* use default */
5314 if (mpt_config(ioc, &cfg) != 0)
5315 return -EFAULT;
5316
5317 if (header.PageLength > 0) {
5318 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5319 if (pbuf) {
5320 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5321 cfg.physAddr = buf_dma;
5322 if (mpt_config(ioc, &cfg) != 0) {
5323 ioc->spi_data.maxBusWidth = MPT_NARROW;
5324 ioc->spi_data.maxSyncOffset = 0;
5325 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5326 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5327 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305328 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5329 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005330 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331 } else {
5332 /* Save the Port Page 0 data
5333 */
5334 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5335 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5336 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5337
5338 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5339 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005340 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5341 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342 ioc->name, pPP0->Capabilities));
5343 }
5344 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5345 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5346 if (data) {
5347 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5348 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5349 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305350 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5351 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005352 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005353 } else {
5354 ioc->spi_data.maxSyncOffset = 0;
5355 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5356 }
5357
5358 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5359
5360 /* Update the minSyncFactor based on bus type.
5361 */
5362 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5363 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5364
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005365 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005366 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305367 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5368 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005369 ioc->name, ioc->spi_data.minSyncFactor));
5370 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371 }
5372 }
5373 if (pbuf) {
5374 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5375 }
5376 }
5377 }
5378
5379 /* SCSI Port Page 2 - Read the header then the page.
5380 */
5381 header.PageVersion = 0;
5382 header.PageLength = 0;
5383 header.PageNumber = 2;
5384 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005385 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 cfg.physAddr = -1;
5387 cfg.pageAddr = portnum;
5388 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5389 cfg.dir = 0;
5390 if (mpt_config(ioc, &cfg) != 0)
5391 return -EFAULT;
5392
5393 if (header.PageLength > 0) {
5394 /* Allocate memory and read SCSI Port Page 2
5395 */
5396 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5397 if (pbuf) {
5398 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5399 cfg.physAddr = buf_dma;
5400 if (mpt_config(ioc, &cfg) != 0) {
5401 /* Nvram data is left with INVALID mark
5402 */
5403 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005404 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5405
5406 /* This is an ATTO adapter, read Page2 accordingly
5407 */
5408 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5409 ATTODeviceInfo_t *pdevice = NULL;
5410 u16 ATTOFlags;
5411
5412 /* Save the Port Page 2 data
5413 * (reformat into a 32bit quantity)
5414 */
5415 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5416 pdevice = &pPP2->DeviceSettings[ii];
5417 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5418 data = 0;
5419
5420 /* Translate ATTO device flags to LSI format
5421 */
5422 if (ATTOFlags & ATTOFLAG_DISC)
5423 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5424 if (ATTOFlags & ATTOFLAG_ID_ENB)
5425 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5426 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5427 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5428 if (ATTOFlags & ATTOFLAG_TAGGED)
5429 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5430 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5431 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5432
5433 data = (data << 16) | (pdevice->Period << 8) | 10;
5434 ioc->spi_data.nvram[ii] = data;
5435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436 } else {
5437 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5438 MpiDeviceInfo_t *pdevice = NULL;
5439
Moore, Ericd8e925d2006-01-16 18:53:06 -07005440 /*
5441 * Save "Set to Avoid SCSI Bus Resets" flag
5442 */
5443 ioc->spi_data.bus_reset =
5444 (le32_to_cpu(pPP2->PortFlags) &
5445 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5446 0 : 1 ;
5447
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 /* Save the Port Page 2 data
5449 * (reformat into a 32bit quantity)
5450 */
5451 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5452 ioc->spi_data.PortFlags = data;
5453 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5454 pdevice = &pPP2->DeviceSettings[ii];
5455 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5456 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5457 ioc->spi_data.nvram[ii] = data;
5458 }
5459 }
5460
5461 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5462 }
5463 }
5464
5465 /* Update Adapter limits with those from NVRAM
5466 * Comment: Don't need to do this. Target performance
5467 * parameters will never exceed the adapters limits.
5468 */
5469
5470 return rc;
5471}
5472
5473/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005474/**
5475 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476 * @ioc: Pointer to a Adapter Strucutre
5477 * @portnum: IOC port number
5478 *
5479 * Return: -EFAULT if read of config page header fails
5480 * or 0 if success.
5481 */
5482static int
5483mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5484{
5485 CONFIGPARMS cfg;
5486 ConfigPageHeader_t header;
5487
5488 /* Read the SCSI Device Page 1 header
5489 */
5490 header.PageVersion = 0;
5491 header.PageLength = 0;
5492 header.PageNumber = 1;
5493 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005494 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 cfg.physAddr = -1;
5496 cfg.pageAddr = portnum;
5497 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5498 cfg.dir = 0;
5499 cfg.timeout = 0;
5500 if (mpt_config(ioc, &cfg) != 0)
5501 return -EFAULT;
5502
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005503 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5504 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505
5506 header.PageVersion = 0;
5507 header.PageLength = 0;
5508 header.PageNumber = 0;
5509 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5510 if (mpt_config(ioc, &cfg) != 0)
5511 return -EFAULT;
5512
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005513 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5514 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515
Prakash, Sathya436ace72007-07-24 15:42:08 +05305516 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5518
Prakash, Sathya436ace72007-07-24 15:42:08 +05305519 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5521 return 0;
5522}
5523
Eric Mooreb506ade2007-01-29 09:45:37 -07005524/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005525 * mpt_inactive_raid_list_free - This clears this link list.
5526 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005527 **/
5528static void
5529mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5530{
5531 struct inactive_raid_component_info *component_info, *pNext;
5532
5533 if (list_empty(&ioc->raid_data.inactive_list))
5534 return;
5535
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005536 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005537 list_for_each_entry_safe(component_info, pNext,
5538 &ioc->raid_data.inactive_list, list) {
5539 list_del(&component_info->list);
5540 kfree(component_info);
5541 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005542 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005543}
5544
5545/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005546 * 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 -07005547 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005548 * @ioc : pointer to per adapter structure
5549 * @channel : volume channel
5550 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005551 **/
5552static void
5553mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5554{
5555 CONFIGPARMS cfg;
5556 ConfigPageHeader_t hdr;
5557 dma_addr_t dma_handle;
5558 pRaidVolumePage0_t buffer = NULL;
5559 int i;
5560 RaidPhysDiskPage0_t phys_disk;
5561 struct inactive_raid_component_info *component_info;
5562 int handle_inactive_volumes;
5563
5564 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5565 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5566 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5567 cfg.pageAddr = (channel << 8) + id;
5568 cfg.cfghdr.hdr = &hdr;
5569 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5570
5571 if (mpt_config(ioc, &cfg) != 0)
5572 goto out;
5573
5574 if (!hdr.PageLength)
5575 goto out;
5576
5577 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5578 &dma_handle);
5579
5580 if (!buffer)
5581 goto out;
5582
5583 cfg.physAddr = dma_handle;
5584 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5585
5586 if (mpt_config(ioc, &cfg) != 0)
5587 goto out;
5588
5589 if (!buffer->NumPhysDisks)
5590 goto out;
5591
5592 handle_inactive_volumes =
5593 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5594 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5595 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5596 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5597
5598 if (!handle_inactive_volumes)
5599 goto out;
5600
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005601 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005602 for (i = 0; i < buffer->NumPhysDisks; i++) {
5603 if(mpt_raid_phys_disk_pg0(ioc,
5604 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5605 continue;
5606
5607 if ((component_info = kmalloc(sizeof (*component_info),
5608 GFP_KERNEL)) == NULL)
5609 continue;
5610
5611 component_info->volumeID = id;
5612 component_info->volumeBus = channel;
5613 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5614 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5615 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5616 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5617
5618 list_add_tail(&component_info->list,
5619 &ioc->raid_data.inactive_list);
5620 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005621 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005622
5623 out:
5624 if (buffer)
5625 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5626 dma_handle);
5627}
5628
5629/**
5630 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5631 * @ioc: Pointer to a Adapter Structure
5632 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5633 * @phys_disk: requested payload data returned
5634 *
5635 * Return:
5636 * 0 on success
5637 * -EFAULT if read of config page header fails or data pointer not NULL
5638 * -ENOMEM if pci_alloc failed
5639 **/
5640int
5641mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5642{
5643 CONFIGPARMS cfg;
5644 ConfigPageHeader_t hdr;
5645 dma_addr_t dma_handle;
5646 pRaidPhysDiskPage0_t buffer = NULL;
5647 int rc;
5648
5649 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5650 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5651
5652 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5653 cfg.cfghdr.hdr = &hdr;
5654 cfg.physAddr = -1;
5655 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5656
5657 if (mpt_config(ioc, &cfg) != 0) {
5658 rc = -EFAULT;
5659 goto out;
5660 }
5661
5662 if (!hdr.PageLength) {
5663 rc = -EFAULT;
5664 goto out;
5665 }
5666
5667 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5668 &dma_handle);
5669
5670 if (!buffer) {
5671 rc = -ENOMEM;
5672 goto out;
5673 }
5674
5675 cfg.physAddr = dma_handle;
5676 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5677 cfg.pageAddr = phys_disk_num;
5678
5679 if (mpt_config(ioc, &cfg) != 0) {
5680 rc = -EFAULT;
5681 goto out;
5682 }
5683
5684 rc = 0;
5685 memcpy(phys_disk, buffer, sizeof(*buffer));
5686 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5687
5688 out:
5689
5690 if (buffer)
5691 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5692 dma_handle);
5693
5694 return rc;
5695}
5696
Linus Torvalds1da177e2005-04-16 15:20:36 -07005697/**
5698 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5699 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700 *
5701 * Return:
5702 * 0 on success
5703 * -EFAULT if read of config page header fails or data pointer not NULL
5704 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005705 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706int
5707mpt_findImVolumes(MPT_ADAPTER *ioc)
5708{
5709 IOCPage2_t *pIoc2;
5710 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005711 dma_addr_t ioc2_dma;
5712 CONFIGPARMS cfg;
5713 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714 int rc = 0;
5715 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005716 int i;
5717
5718 if (!ioc->ir_firmware)
5719 return 0;
5720
5721 /* Free the old page
5722 */
5723 kfree(ioc->raid_data.pIocPg2);
5724 ioc->raid_data.pIocPg2 = NULL;
5725 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005726
5727 /* Read IOCP2 header then the page.
5728 */
5729 header.PageVersion = 0;
5730 header.PageLength = 0;
5731 header.PageNumber = 2;
5732 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005733 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005734 cfg.physAddr = -1;
5735 cfg.pageAddr = 0;
5736 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5737 cfg.dir = 0;
5738 cfg.timeout = 0;
5739 if (mpt_config(ioc, &cfg) != 0)
5740 return -EFAULT;
5741
5742 if (header.PageLength == 0)
5743 return -EFAULT;
5744
5745 iocpage2sz = header.PageLength * 4;
5746 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5747 if (!pIoc2)
5748 return -ENOMEM;
5749
5750 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5751 cfg.physAddr = ioc2_dma;
5752 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005753 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005754
Eric Mooreb506ade2007-01-29 09:45:37 -07005755 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5756 if (!mem)
5757 goto out;
5758
Linus Torvalds1da177e2005-04-16 15:20:36 -07005759 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005760 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005761
Eric Mooreb506ade2007-01-29 09:45:37 -07005762 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005763
Eric Mooreb506ade2007-01-29 09:45:37 -07005764 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5765 mpt_inactive_raid_volumes(ioc,
5766 pIoc2->RaidVolume[i].VolumeBus,
5767 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768
Eric Mooreb506ade2007-01-29 09:45:37 -07005769 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5771
5772 return rc;
5773}
5774
Moore, Ericc972c702006-03-14 09:14:06 -07005775static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005776mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5777{
5778 IOCPage3_t *pIoc3;
5779 u8 *mem;
5780 CONFIGPARMS cfg;
5781 ConfigPageHeader_t header;
5782 dma_addr_t ioc3_dma;
5783 int iocpage3sz = 0;
5784
5785 /* Free the old page
5786 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005787 kfree(ioc->raid_data.pIocPg3);
5788 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789
5790 /* There is at least one physical disk.
5791 * Read and save IOC Page 3
5792 */
5793 header.PageVersion = 0;
5794 header.PageLength = 0;
5795 header.PageNumber = 3;
5796 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005797 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798 cfg.physAddr = -1;
5799 cfg.pageAddr = 0;
5800 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5801 cfg.dir = 0;
5802 cfg.timeout = 0;
5803 if (mpt_config(ioc, &cfg) != 0)
5804 return 0;
5805
5806 if (header.PageLength == 0)
5807 return 0;
5808
5809 /* Read Header good, alloc memory
5810 */
5811 iocpage3sz = header.PageLength * 4;
5812 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5813 if (!pIoc3)
5814 return 0;
5815
5816 /* Read the Page and save the data
5817 * into malloc'd memory.
5818 */
5819 cfg.physAddr = ioc3_dma;
5820 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5821 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005822 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005823 if (mem) {
5824 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005825 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005826 }
5827 }
5828
5829 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5830
5831 return 0;
5832}
5833
5834static void
5835mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5836{
5837 IOCPage4_t *pIoc4;
5838 CONFIGPARMS cfg;
5839 ConfigPageHeader_t header;
5840 dma_addr_t ioc4_dma;
5841 int iocpage4sz;
5842
5843 /* Read and save IOC Page 4
5844 */
5845 header.PageVersion = 0;
5846 header.PageLength = 0;
5847 header.PageNumber = 4;
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;
5857
5858 if (header.PageLength == 0)
5859 return;
5860
5861 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5862 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5863 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5864 if (!pIoc4)
5865 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005866 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867 } else {
5868 ioc4_dma = ioc->spi_data.IocPg4_dma;
5869 iocpage4sz = ioc->spi_data.IocPg4Sz;
5870 }
5871
5872 /* Read the Page into dma memory.
5873 */
5874 cfg.physAddr = ioc4_dma;
5875 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5876 if (mpt_config(ioc, &cfg) == 0) {
5877 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5878 ioc->spi_data.IocPg4_dma = ioc4_dma;
5879 ioc->spi_data.IocPg4Sz = iocpage4sz;
5880 } else {
5881 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5882 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005883 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005884 }
5885}
5886
5887static void
5888mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5889{
5890 IOCPage1_t *pIoc1;
5891 CONFIGPARMS cfg;
5892 ConfigPageHeader_t header;
5893 dma_addr_t ioc1_dma;
5894 int iocpage1sz = 0;
5895 u32 tmp;
5896
5897 /* Check the Coalescing Timeout in IOC Page 1
5898 */
5899 header.PageVersion = 0;
5900 header.PageLength = 0;
5901 header.PageNumber = 1;
5902 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005903 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005904 cfg.physAddr = -1;
5905 cfg.pageAddr = 0;
5906 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5907 cfg.dir = 0;
5908 cfg.timeout = 0;
5909 if (mpt_config(ioc, &cfg) != 0)
5910 return;
5911
5912 if (header.PageLength == 0)
5913 return;
5914
5915 /* Read Header good, alloc memory
5916 */
5917 iocpage1sz = header.PageLength * 4;
5918 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5919 if (!pIoc1)
5920 return;
5921
5922 /* Read the Page and check coalescing timeout
5923 */
5924 cfg.physAddr = ioc1_dma;
5925 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5926 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305927
Linus Torvalds1da177e2005-04-16 15:20:36 -07005928 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5929 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5930 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5931
Prakash, Sathya436ace72007-07-24 15:42:08 +05305932 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005933 ioc->name, tmp));
5934
5935 if (tmp > MPT_COALESCING_TIMEOUT) {
5936 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5937
5938 /* Write NVRAM and current
5939 */
5940 cfg.dir = 1;
5941 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5942 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305943 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005944 ioc->name, MPT_COALESCING_TIMEOUT));
5945
5946 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5947 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305948 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5949 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005950 ioc->name, MPT_COALESCING_TIMEOUT));
5951 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305952 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5953 "Reset NVRAM Coalescing Timeout Failed\n",
5954 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955 }
5956
5957 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305958 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5959 "Reset of Current Coalescing Timeout Failed!\n",
5960 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005961 }
5962 }
5963
5964 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305965 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005966 }
5967 }
5968
5969 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5970
5971 return;
5972}
5973
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305974static void
5975mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5976{
5977 CONFIGPARMS cfg;
5978 ConfigPageHeader_t hdr;
5979 dma_addr_t buf_dma;
5980 ManufacturingPage0_t *pbuf = NULL;
5981
5982 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5983 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5984
5985 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5986 cfg.cfghdr.hdr = &hdr;
5987 cfg.physAddr = -1;
5988 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5989 cfg.timeout = 10;
5990
5991 if (mpt_config(ioc, &cfg) != 0)
5992 goto out;
5993
5994 if (!cfg.cfghdr.hdr->PageLength)
5995 goto out;
5996
5997 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5998 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5999 if (!pbuf)
6000 goto out;
6001
6002 cfg.physAddr = buf_dma;
6003
6004 if (mpt_config(ioc, &cfg) != 0)
6005 goto out;
6006
6007 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
6008 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
6009 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
6010
6011 out:
6012
6013 if (pbuf)
6014 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
6015}
6016
Linus Torvalds1da177e2005-04-16 15:20:36 -07006017/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006018/**
6019 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006020 * @ioc: Pointer to MPT_ADAPTER structure
6021 * @EvSwitch: Event switch flags
6022 */
6023static int
6024SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch)
6025{
6026 EventNotification_t *evnp;
6027
6028 evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
6029 if (evnp == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306030 devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006031 ioc->name));
6032 return 0;
6033 }
6034 memset(evnp, 0, sizeof(*evnp));
6035
Prakash, Sathya436ace72007-07-24 15:42:08 +05306036 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006037
6038 evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
6039 evnp->ChainOffset = 0;
6040 evnp->MsgFlags = 0;
6041 evnp->Switch = EvSwitch;
6042
6043 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)evnp);
6044
6045 return 0;
6046}
6047
6048/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6049/**
6050 * SendEventAck - Send EventAck request to MPT adapter.
6051 * @ioc: Pointer to MPT_ADAPTER structure
6052 * @evnp: Pointer to original EventNotification request
6053 */
6054static int
6055SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6056{
6057 EventAck_t *pAck;
6058
6059 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306060 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07006061 ioc->name,__func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006062 return -1;
6063 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064
Prakash, Sathya436ace72007-07-24 15:42:08 +05306065 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006066
6067 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6068 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006069 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006071 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072 pAck->Event = evnp->Event;
6073 pAck->EventContext = evnp->EventContext;
6074
6075 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6076
6077 return 0;
6078}
6079
6080/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6081/**
6082 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006083 * @ioc: Pointer to an adapter structure
6084 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085 * action, page address, direction, physical address
6086 * and pointer to a configuration page header
6087 * Page header is updated.
6088 *
6089 * Returns 0 for success
6090 * -EPERM if not allowed due to ISR context
6091 * -EAGAIN if no msg frames currently available
6092 * -EFAULT for non-successful reply or no reply (timeout)
6093 */
6094int
6095mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6096{
6097 Config_t *pReq;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006098 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006099 MPT_FRAME_HDR *mf;
6100 unsigned long flags;
6101 int ii, rc;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006102 int flagsLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103 int in_isr;
6104
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006105 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006106 * to be in ISR context, because that is fatal!
6107 */
6108 in_isr = in_interrupt();
6109 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306110 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006111 ioc->name));
6112 return -EPERM;
6113 }
6114
6115 /* Get and Populate a free Frame
6116 */
6117 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306118 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006119 ioc->name));
6120 return -EAGAIN;
6121 }
6122 pReq = (Config_t *)mf;
6123 pReq->Action = pCfg->action;
6124 pReq->Reserved = 0;
6125 pReq->ChainOffset = 0;
6126 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006127
6128 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006129 pReq->ExtPageLength = 0;
6130 pReq->ExtPageType = 0;
6131 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006132
Linus Torvalds1da177e2005-04-16 15:20:36 -07006133 for (ii=0; ii < 8; ii++)
6134 pReq->Reserved2[ii] = 0;
6135
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006136 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6137 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6138 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6139 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6140
6141 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6142 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6143 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6144 pReq->ExtPageType = pExtHdr->ExtPageType;
6145 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6146
6147 /* Page Length must be treated as a reserved field for the extended header. */
6148 pReq->Header.PageLength = 0;
6149 }
6150
Linus Torvalds1da177e2005-04-16 15:20:36 -07006151 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6152
6153 /* Add a SGE to the config request.
6154 */
6155 if (pCfg->dir)
6156 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6157 else
6158 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6159
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006160 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6161 flagsLength |= pExtHdr->ExtPageLength * 4;
6162
Prakash, Sathya436ace72007-07-24 15:42:08 +05306163 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n",
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006164 ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
6165 }
6166 else {
6167 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
6168
Prakash, Sathya436ace72007-07-24 15:42:08 +05306169 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n",
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006170 ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
6171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006172
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306173 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006174
Linus Torvalds1da177e2005-04-16 15:20:36 -07006175 /* Append pCfg pointer to end of mf
6176 */
6177 *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg;
6178
6179 /* Initalize the timer
6180 */
Eric Parisb298cec2009-04-21 12:24:54 -07006181 init_timer_on_stack(&pCfg->timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006182 pCfg->timer.data = (unsigned long) ioc;
6183 pCfg->timer.function = mpt_timer_expired;
6184 pCfg->wait_done = 0;
6185
6186 /* Set the timer; ensure 10 second minimum */
6187 if (pCfg->timeout < 10)
6188 pCfg->timer.expires = jiffies + HZ*10;
6189 else
6190 pCfg->timer.expires = jiffies + HZ*pCfg->timeout;
6191
6192 /* Add to end of Q, set timer and then issue this command */
6193 spin_lock_irqsave(&ioc->FreeQlock, flags);
6194 list_add_tail(&pCfg->linkage, &ioc->configQ);
6195 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
6196
6197 add_timer(&pCfg->timer);
6198 mpt_put_msg_frame(mpt_base_index, ioc, mf);
6199 wait_event(mpt_waitq, pCfg->wait_done);
6200
6201 /* mf has been freed - do not access */
6202
6203 rc = pCfg->status;
6204
6205 return rc;
6206}
6207
6208/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006209/**
6210 * mpt_timer_expired - Callback for timer process.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211 * Used only internal config functionality.
6212 * @data: Pointer to MPT_SCSI_HOST recast as an unsigned long
6213 */
6214static void
6215mpt_timer_expired(unsigned long data)
6216{
6217 MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
6218
Prakash, Sathya436ace72007-07-24 15:42:08 +05306219 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006220
6221 /* Perform a FW reload */
6222 if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
6223 printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
6224
6225 /* No more processing.
6226 * Hard reset clean-up will wake up
6227 * process and free all resources.
6228 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05306229 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006230
6231 return;
6232}
6233
6234/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006235/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006236 * mpt_ioc_reset - Base cleanup for hard reset
6237 * @ioc: Pointer to the adapter structure
6238 * @reset_phase: Indicates pre- or post-reset functionality
6239 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006240 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241 */
6242static int
6243mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6244{
6245 CONFIGPARMS *pCfg;
6246 unsigned long flags;
6247
Eric Moore29dd3602007-09-14 18:46:51 -06006248 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6249 ": IOC %s_reset routed to MPT base driver!\n",
6250 ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
6251 reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006252
6253 if (reset_phase == MPT_IOC_SETUP_RESET) {
6254 ;
6255 } else if (reset_phase == MPT_IOC_PRE_RESET) {
6256 /* If the internal config Q is not empty -
6257 * delete timer. MF resources will be freed when
6258 * the FIFO's are primed.
6259 */
6260 spin_lock_irqsave(&ioc->FreeQlock, flags);
6261 list_for_each_entry(pCfg, &ioc->configQ, linkage)
6262 del_timer(&pCfg->timer);
6263 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
6264
6265 } else {
6266 CONFIGPARMS *pNext;
6267
6268 /* Search the configQ for internal commands.
6269 * Flush the Q, and wake up all suspended threads.
6270 */
6271 spin_lock_irqsave(&ioc->FreeQlock, flags);
6272 list_for_each_entry_safe(pCfg, pNext, &ioc->configQ, linkage) {
6273 list_del(&pCfg->linkage);
6274
6275 pCfg->status = MPT_CONFIG_ERROR;
6276 pCfg->wait_done = 1;
6277 wake_up(&mpt_waitq);
6278 }
6279 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
6280 }
6281
6282 return 1; /* currently means nothing really */
6283}
6284
6285
6286#ifdef CONFIG_PROC_FS /* { */
6287/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6288/*
6289 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6290 */
6291/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006292/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006293 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6294 *
6295 * Returns 0 for success, non-zero for failure.
6296 */
6297static int
6298procmpt_create(void)
6299{
6300 struct proc_dir_entry *ent;
6301
6302 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6303 if (mpt_proc_root_dir == NULL)
6304 return -ENOTDIR;
6305
6306 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6307 if (ent)
6308 ent->read_proc = procmpt_summary_read;
6309
6310 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6311 if (ent)
6312 ent->read_proc = procmpt_version_read;
6313
6314 return 0;
6315}
6316
6317/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006318/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006319 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6320 *
6321 * Returns 0 for success, non-zero for failure.
6322 */
6323static void
6324procmpt_destroy(void)
6325{
6326 remove_proc_entry("version", mpt_proc_root_dir);
6327 remove_proc_entry("summary", mpt_proc_root_dir);
6328 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6329}
6330
6331/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006332/**
6333 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006334 * @buf: Pointer to area to write information
6335 * @start: Pointer to start pointer
6336 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006337 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338 * @eof: Pointer to EOF integer
6339 * @data: Pointer
6340 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006341 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006342 * Returns number of characters written to process performing the read.
6343 */
6344static int
6345procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6346{
6347 MPT_ADAPTER *ioc;
6348 char *out = buf;
6349 int len;
6350
6351 if (data) {
6352 int more = 0;
6353
6354 ioc = data;
6355 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6356
6357 out += more;
6358 } else {
6359 list_for_each_entry(ioc, &ioc_list, list) {
6360 int more = 0;
6361
6362 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6363
6364 out += more;
6365 if ((out-buf) >= request)
6366 break;
6367 }
6368 }
6369
6370 len = out - buf;
6371
6372 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6373}
6374
6375/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006376/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006377 * procmpt_version_read - Handle read request from /proc/mpt/version.
6378 * @buf: Pointer to area to write information
6379 * @start: Pointer to start pointer
6380 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006381 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006382 * @eof: Pointer to EOF integer
6383 * @data: Pointer
6384 *
6385 * Returns number of characters written to process performing the read.
6386 */
6387static int
6388procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6389{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306390 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006391 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006392 char *drvname;
6393 int len;
6394
6395 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6396 len += sprintf(buf+len, " Fusion MPT base driver\n");
6397
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006398 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006399 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006400 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306401 if (MptCallbacks[cb_idx]) {
6402 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006403 case MPTSPI_DRIVER:
6404 if (!scsi++) drvname = "SPI host";
6405 break;
6406 case MPTFC_DRIVER:
6407 if (!fc++) drvname = "FC host";
6408 break;
6409 case MPTSAS_DRIVER:
6410 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006411 break;
6412 case MPTLAN_DRIVER:
6413 if (!lan++) drvname = "LAN";
6414 break;
6415 case MPTSTM_DRIVER:
6416 if (!targ++) drvname = "SCSI target";
6417 break;
6418 case MPTCTL_DRIVER:
6419 if (!ctl++) drvname = "ioctl";
6420 break;
6421 }
6422
6423 if (drvname)
6424 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6425 }
6426 }
6427
6428 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6429}
6430
6431/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006432/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006433 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6434 * @buf: Pointer to area to write information
6435 * @start: Pointer to start pointer
6436 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006437 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006438 * @eof: Pointer to EOF integer
6439 * @data: Pointer
6440 *
6441 * Returns number of characters written to process performing the read.
6442 */
6443static int
6444procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6445{
6446 MPT_ADAPTER *ioc = data;
6447 int len;
6448 char expVer[32];
6449 int sz;
6450 int p;
6451
6452 mpt_get_fw_exp_ver(expVer, ioc);
6453
6454 len = sprintf(buf, "%s:", ioc->name);
6455 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6456 len += sprintf(buf+len, " (f/w download boot flag set)");
6457// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6458// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6459
6460 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6461 ioc->facts.ProductID,
6462 ioc->prod_name);
6463 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6464 if (ioc->facts.FWImageSize)
6465 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6466 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6467 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6468 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6469
6470 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6471 ioc->facts.CurrentHostMfaHighAddr);
6472 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6473 ioc->facts.CurrentSenseBufferHighAddr);
6474
6475 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6476 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6477
6478 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6479 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6480 /*
6481 * Rounding UP to nearest 4-kB boundary here...
6482 */
6483 sz = (ioc->req_sz * ioc->req_depth) + 128;
6484 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6485 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6486 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6487 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6488 4*ioc->facts.RequestFrameSize,
6489 ioc->facts.GlobalCredits);
6490
6491 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6492 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6493 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6494 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6495 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6496 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6497 ioc->facts.CurReplyFrameSize,
6498 ioc->facts.ReplyQueueDepth);
6499
6500 len += sprintf(buf+len, " MaxDevices = %d\n",
6501 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6502 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6503
6504 /* per-port info */
6505 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6506 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6507 p+1,
6508 ioc->facts.NumberOfPorts);
6509 if (ioc->bus_type == FC) {
6510 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6511 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6512 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6513 a[5], a[4], a[3], a[2], a[1], a[0]);
6514 }
6515 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6516 ioc->fc_port_page0[p].WWNN.High,
6517 ioc->fc_port_page0[p].WWNN.Low,
6518 ioc->fc_port_page0[p].WWPN.High,
6519 ioc->fc_port_page0[p].WWPN.Low);
6520 }
6521 }
6522
6523 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6524}
6525
6526#endif /* CONFIG_PROC_FS } */
6527
6528/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6529static void
6530mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6531{
6532 buf[0] ='\0';
6533 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6534 sprintf(buf, " (Exp %02d%02d)",
6535 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6536 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6537
6538 /* insider hack! */
6539 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6540 strcat(buf, " [MDBG]");
6541 }
6542}
6543
6544/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6545/**
6546 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6547 * @ioc: Pointer to MPT_ADAPTER structure
6548 * @buffer: Pointer to buffer where IOC summary info should be written
6549 * @size: Pointer to number of bytes we wrote (set by this routine)
6550 * @len: Offset at which to start writing in buffer
6551 * @showlan: Display LAN stuff?
6552 *
6553 * This routine writes (english readable) ASCII text, which represents
6554 * a summary of IOC information, to a buffer.
6555 */
6556void
6557mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6558{
6559 char expVer[32];
6560 int y;
6561
6562 mpt_get_fw_exp_ver(expVer, ioc);
6563
6564 /*
6565 * Shorter summary of attached ioc's...
6566 */
6567 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6568 ioc->name,
6569 ioc->prod_name,
6570 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6571 ioc->facts.FWVersion.Word,
6572 expVer,
6573 ioc->facts.NumberOfPorts,
6574 ioc->req_depth);
6575
6576 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6577 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6578 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6579 a[5], a[4], a[3], a[2], a[1], a[0]);
6580 }
6581
Linus Torvalds1da177e2005-04-16 15:20:36 -07006582 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006583
6584 if (!ioc->active)
6585 y += sprintf(buffer+len+y, " (disabled)");
6586
6587 y += sprintf(buffer+len+y, "\n");
6588
6589 *size = y;
6590}
6591
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306592
6593/**
6594 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6595 * the kernel
6596 * @ioc: Pointer to MPT_ADAPTER structure
6597 *
6598 **/
6599void
6600mpt_halt_firmware(MPT_ADAPTER *ioc)
6601{
6602 u32 ioc_raw_state;
6603
6604 ioc_raw_state = mpt_GetIocState(ioc, 0);
6605
6606 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6607 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6608 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6609 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6610 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6611 } else {
6612 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6613 panic("%s: Firmware is halted due to command timeout\n",
6614 ioc->name);
6615 }
6616}
6617EXPORT_SYMBOL(mpt_halt_firmware);
6618
Linus Torvalds1da177e2005-04-16 15:20:36 -07006619/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6620/*
6621 * Reset Handling
6622 */
6623/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6624/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006625 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006626 * @ioc: Pointer to MPT_ADAPTER structure
6627 * @sleepFlag: Indicates if sleep or schedule must be called.
6628 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006629 * Issues SCSI Task Management call based on input arg values.
6630 * If TaskMgmt fails, returns associated SCSI request.
6631 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006632 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6633 * or a non-interrupt thread. In the former, must not call schedule().
6634 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006635 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006636 * FW reload/initialization failed.
6637 *
6638 * Returns 0 for SUCCESS or -1 if FAILED.
6639 */
6640int
6641mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6642{
6643 int rc;
6644 unsigned long flags;
6645
Prakash, Sathya436ace72007-07-24 15:42:08 +05306646 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006647#ifdef MFCNT
6648 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6649 printk("MF count 0x%x !\n", ioc->mfcnt);
6650#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306651 if (mpt_fwfault_debug)
6652 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006653
6654 /* Reset the adapter. Prevent more than 1 call to
6655 * mpt_do_ioc_recovery at any instant in time.
6656 */
6657 spin_lock_irqsave(&ioc->diagLock, flags);
6658 if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)){
6659 spin_unlock_irqrestore(&ioc->diagLock, flags);
6660 return 0;
6661 } else {
6662 ioc->diagPending = 1;
6663 }
6664 spin_unlock_irqrestore(&ioc->diagLock, flags);
6665
6666 /* FIXME: If do_ioc_recovery fails, repeat....
6667 */
6668
6669 /* The SCSI driver needs to adjust timeouts on all current
6670 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006671 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006672 * For all other protocol drivers, this is a no-op.
6673 */
6674 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306675 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006676 int r = 0;
6677
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306678 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6679 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306680 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306681 ioc->name, cb_idx));
6682 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006683 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306684 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306685 ioc->name, ioc->alt_ioc->name, cb_idx));
6686 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006687 }
6688 }
6689 }
6690 }
6691
6692 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06006693 printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006694 }
6695 ioc->reload_fw = 0;
6696 if (ioc->alt_ioc)
6697 ioc->alt_ioc->reload_fw = 0;
6698
6699 spin_lock_irqsave(&ioc->diagLock, flags);
6700 ioc->diagPending = 0;
6701 if (ioc->alt_ioc)
6702 ioc->alt_ioc->diagPending = 0;
6703 spin_unlock_irqrestore(&ioc->diagLock, flags);
6704
Prakash, Sathya436ace72007-07-24 15:42:08 +05306705 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006706
6707 return rc;
6708}
6709
6710/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006711static void
6712EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006713{
Eric Moore509e5e52006-04-26 13:22:37 -06006714 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006715
6716 switch(event) {
6717 case MPI_EVENT_NONE:
6718 ds = "None";
6719 break;
6720 case MPI_EVENT_LOG_DATA:
6721 ds = "Log Data";
6722 break;
6723 case MPI_EVENT_STATE_CHANGE:
6724 ds = "State Change";
6725 break;
6726 case MPI_EVENT_UNIT_ATTENTION:
6727 ds = "Unit Attention";
6728 break;
6729 case MPI_EVENT_IOC_BUS_RESET:
6730 ds = "IOC Bus Reset";
6731 break;
6732 case MPI_EVENT_EXT_BUS_RESET:
6733 ds = "External Bus Reset";
6734 break;
6735 case MPI_EVENT_RESCAN:
6736 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006737 break;
6738 case MPI_EVENT_LINK_STATUS_CHANGE:
6739 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6740 ds = "Link Status(FAILURE) Change";
6741 else
6742 ds = "Link Status(ACTIVE) Change";
6743 break;
6744 case MPI_EVENT_LOOP_STATE_CHANGE:
6745 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6746 ds = "Loop State(LIP) Change";
6747 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006748 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006749 else
Eric Moore509e5e52006-04-26 13:22:37 -06006750 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006751 break;
6752 case MPI_EVENT_LOGOUT:
6753 ds = "Logout";
6754 break;
6755 case MPI_EVENT_EVENT_CHANGE:
6756 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006757 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006758 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006759 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006760 break;
6761 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006762 {
6763 u8 ReasonCode = (u8)(evData0 >> 16);
6764 switch (ReasonCode) {
6765 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6766 ds = "Integrated Raid: Volume Created";
6767 break;
6768 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6769 ds = "Integrated Raid: Volume Deleted";
6770 break;
6771 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6772 ds = "Integrated Raid: Volume Settings Changed";
6773 break;
6774 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6775 ds = "Integrated Raid: Volume Status Changed";
6776 break;
6777 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6778 ds = "Integrated Raid: Volume Physdisk Changed";
6779 break;
6780 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6781 ds = "Integrated Raid: Physdisk Created";
6782 break;
6783 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6784 ds = "Integrated Raid: Physdisk Deleted";
6785 break;
6786 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6787 ds = "Integrated Raid: Physdisk Settings Changed";
6788 break;
6789 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6790 ds = "Integrated Raid: Physdisk Status Changed";
6791 break;
6792 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6793 ds = "Integrated Raid: Domain Validation Needed";
6794 break;
6795 case MPI_EVENT_RAID_RC_SMART_DATA :
6796 ds = "Integrated Raid; Smart Data";
6797 break;
6798 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6799 ds = "Integrated Raid: Replace Action Started";
6800 break;
6801 default:
6802 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006803 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006804 }
6805 break;
6806 }
6807 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6808 ds = "SCSI Device Status Change";
6809 break;
6810 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6811 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006812 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006813 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006814 u8 ReasonCode = (u8)(evData0 >> 16);
6815 switch (ReasonCode) {
6816 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006817 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006818 "SAS Device Status Change: Added: "
6819 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006820 break;
6821 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006822 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006823 "SAS Device Status Change: Deleted: "
6824 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006825 break;
6826 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006827 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006828 "SAS Device Status Change: SMART Data: "
6829 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006830 break;
6831 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006832 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006833 "SAS Device Status Change: No Persistancy: "
6834 "id=%d channel=%d", id, channel);
6835 break;
6836 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6837 snprintf(evStr, EVENT_DESCR_STR_SZ,
6838 "SAS Device Status Change: Unsupported Device "
6839 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006840 break;
6841 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6842 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006843 "SAS Device Status Change: Internal Device "
6844 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006845 break;
6846 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6847 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006848 "SAS Device Status Change: Internal Task "
6849 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006850 break;
6851 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6852 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006853 "SAS Device Status Change: Internal Abort "
6854 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006855 break;
6856 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6857 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006858 "SAS Device Status Change: Internal Clear "
6859 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006860 break;
6861 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6862 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006863 "SAS Device Status Change: Internal Query "
6864 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006865 break;
6866 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006867 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006868 "SAS Device Status Change: Unknown: "
6869 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006870 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006871 }
6872 break;
6873 }
6874 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6875 ds = "Bus Timer Expired";
6876 break;
6877 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006878 {
6879 u16 curr_depth = (u16)(evData0 >> 16);
6880 u8 channel = (u8)(evData0 >> 8);
6881 u8 id = (u8)(evData0);
6882
6883 snprintf(evStr, EVENT_DESCR_STR_SZ,
6884 "Queue Full: channel=%d id=%d depth=%d",
6885 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006886 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006887 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006888 case MPI_EVENT_SAS_SES:
6889 ds = "SAS SES Event";
6890 break;
6891 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6892 ds = "Persistent Table Full";
6893 break;
6894 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006895 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006896 u8 LinkRates = (u8)(evData0 >> 8);
6897 u8 PhyNumber = (u8)(evData0);
6898 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6899 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6900 switch (LinkRates) {
6901 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006902 snprintf(evStr, EVENT_DESCR_STR_SZ,
6903 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006904 " Rate Unknown",PhyNumber);
6905 break;
6906 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006907 snprintf(evStr, EVENT_DESCR_STR_SZ,
6908 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006909 " Phy Disabled",PhyNumber);
6910 break;
6911 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006912 snprintf(evStr, EVENT_DESCR_STR_SZ,
6913 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006914 " Failed Speed Nego",PhyNumber);
6915 break;
6916 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006917 snprintf(evStr, EVENT_DESCR_STR_SZ,
6918 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006919 " Sata OOB Completed",PhyNumber);
6920 break;
6921 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006922 snprintf(evStr, EVENT_DESCR_STR_SZ,
6923 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006924 " Rate 1.5 Gbps",PhyNumber);
6925 break;
6926 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006927 snprintf(evStr, EVENT_DESCR_STR_SZ,
6928 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006929 " Rate 3.0 Gpbs",PhyNumber);
6930 break;
6931 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006932 snprintf(evStr, EVENT_DESCR_STR_SZ,
6933 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006934 break;
6935 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006936 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006937 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006938 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6939 ds = "SAS Discovery Error";
6940 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006941 case MPI_EVENT_IR_RESYNC_UPDATE:
6942 {
6943 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006944 snprintf(evStr, EVENT_DESCR_STR_SZ,
6945 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006946 break;
6947 }
6948 case MPI_EVENT_IR2:
6949 {
6950 u8 ReasonCode = (u8)(evData0 >> 16);
6951 switch (ReasonCode) {
6952 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6953 ds = "IR2: LD State Changed";
6954 break;
6955 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
6956 ds = "IR2: PD State Changed";
6957 break;
6958 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
6959 ds = "IR2: Bad Block Table Full";
6960 break;
6961 case MPI_EVENT_IR2_RC_PD_INSERTED:
6962 ds = "IR2: PD Inserted";
6963 break;
6964 case MPI_EVENT_IR2_RC_PD_REMOVED:
6965 ds = "IR2: PD Removed";
6966 break;
6967 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
6968 ds = "IR2: Foreign CFG Detected";
6969 break;
6970 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
6971 ds = "IR2: Rebuild Medium Error";
6972 break;
6973 default:
6974 ds = "IR2";
6975 break;
6976 }
6977 break;
6978 }
6979 case MPI_EVENT_SAS_DISCOVERY:
6980 {
6981 if (evData0)
6982 ds = "SAS Discovery: Start";
6983 else
6984 ds = "SAS Discovery: Stop";
6985 break;
6986 }
6987 case MPI_EVENT_LOG_ENTRY_ADDED:
6988 ds = "SAS Log Entry Added";
6989 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006990
Eric Moorec6c727a2007-01-29 09:44:54 -07006991 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
6992 {
6993 u8 phy_num = (u8)(evData0);
6994 u8 port_num = (u8)(evData0 >> 8);
6995 u8 port_width = (u8)(evData0 >> 16);
6996 u8 primative = (u8)(evData0 >> 24);
6997 snprintf(evStr, EVENT_DESCR_STR_SZ,
6998 "SAS Broadcase Primative: phy=%d port=%d "
6999 "width=%d primative=0x%02x",
7000 phy_num, port_num, port_width, primative);
7001 break;
7002 }
7003
7004 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7005 {
7006 u8 reason = (u8)(evData0);
7007 u8 port_num = (u8)(evData0 >> 8);
7008 u16 handle = le16_to_cpu(evData0 >> 16);
7009
7010 snprintf(evStr, EVENT_DESCR_STR_SZ,
7011 "SAS Initiator Device Status Change: reason=0x%02x "
7012 "port=%d handle=0x%04x",
7013 reason, port_num, handle);
7014 break;
7015 }
7016
7017 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7018 {
7019 u8 max_init = (u8)(evData0);
7020 u8 current_init = (u8)(evData0 >> 8);
7021
7022 snprintf(evStr, EVENT_DESCR_STR_SZ,
7023 "SAS Initiator Device Table Overflow: max initiators=%02d "
7024 "current initators=%02d",
7025 max_init, current_init);
7026 break;
7027 }
7028 case MPI_EVENT_SAS_SMP_ERROR:
7029 {
7030 u8 status = (u8)(evData0);
7031 u8 port_num = (u8)(evData0 >> 8);
7032 u8 result = (u8)(evData0 >> 16);
7033
7034 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7035 snprintf(evStr, EVENT_DESCR_STR_SZ,
7036 "SAS SMP Error: port=%d result=0x%02x",
7037 port_num, result);
7038 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7039 snprintf(evStr, EVENT_DESCR_STR_SZ,
7040 "SAS SMP Error: port=%d : CRC Error",
7041 port_num);
7042 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7043 snprintf(evStr, EVENT_DESCR_STR_SZ,
7044 "SAS SMP Error: port=%d : Timeout",
7045 port_num);
7046 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7047 snprintf(evStr, EVENT_DESCR_STR_SZ,
7048 "SAS SMP Error: port=%d : No Destination",
7049 port_num);
7050 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7051 snprintf(evStr, EVENT_DESCR_STR_SZ,
7052 "SAS SMP Error: port=%d : Bad Destination",
7053 port_num);
7054 else
7055 snprintf(evStr, EVENT_DESCR_STR_SZ,
7056 "SAS SMP Error: port=%d : status=0x%02x",
7057 port_num, status);
7058 break;
7059 }
7060
Linus Torvalds1da177e2005-04-16 15:20:36 -07007061 /*
7062 * MPT base "custom" events may be added here...
7063 */
7064 default:
7065 ds = "Unknown";
7066 break;
7067 }
Eric Moore509e5e52006-04-26 13:22:37 -06007068 if (ds)
7069 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007070}
7071
7072/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007073/**
7074 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007075 * @ioc: Pointer to MPT_ADAPTER structure
7076 * @pEventReply: Pointer to EventNotification reply frame
7077 * @evHandlers: Pointer to integer, number of event handlers
7078 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007079 * Routes a received EventNotificationReply to all currently registered
7080 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007081 * Returns sum of event handlers return values.
7082 */
7083static int
7084ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7085{
7086 u16 evDataLen;
7087 u32 evData0 = 0;
7088// u32 evCtx;
7089 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307090 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007091 int r = 0;
7092 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06007093 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007094 u8 event;
7095
7096 /*
7097 * Do platform normalization of values
7098 */
7099 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7100// evCtx = le32_to_cpu(pEventReply->EventContext);
7101 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7102 if (evDataLen) {
7103 evData0 = le32_to_cpu(pEventReply->Data[0]);
7104 }
7105
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007106 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05307107 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007108 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07007109 event,
7110 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007111
Prakash, Sathya436ace72007-07-24 15:42:08 +05307112#ifdef CONFIG_FUSION_LOGGING
Eric Moore29dd3602007-09-14 18:46:51 -06007113 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7114 ": Event data:\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007115 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05307116 devtverboseprintk(ioc, printk(" %08x",
7117 le32_to_cpu(pEventReply->Data[ii])));
Eric Moore29dd3602007-09-14 18:46:51 -06007118 devtverboseprintk(ioc, printk("\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007119#endif
7120
7121 /*
7122 * Do general / base driver event processing
7123 */
7124 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007125 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7126 if (evDataLen) {
7127 u8 evState = evData0 & 0xFF;
7128
7129 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7130
7131 /* Update EventState field in cached IocFacts */
7132 if (ioc->facts.Function) {
7133 ioc->facts.EventState = evState;
7134 }
7135 }
7136 break;
Moore, Ericece50912006-01-16 18:53:19 -07007137 case MPI_EVENT_INTEGRATED_RAID:
7138 mptbase_raid_process_event_data(ioc,
7139 (MpiEventDataRaid_t *)pEventReply->Data);
7140 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007141 default:
7142 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007143 }
7144
7145 /*
7146 * Should this event be logged? Events are written sequentially.
7147 * When buffer is full, start again at the top.
7148 */
7149 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7150 int idx;
7151
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007152 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007153
7154 ioc->events[idx].event = event;
7155 ioc->events[idx].eventContext = ioc->eventContext;
7156
7157 for (ii = 0; ii < 2; ii++) {
7158 if (ii < evDataLen)
7159 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7160 else
7161 ioc->events[idx].data[ii] = 0;
7162 }
7163
7164 ioc->eventContext++;
7165 }
7166
7167
7168 /*
7169 * Call each currently registered protocol event handler.
7170 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007171 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307172 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307173 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307174 ioc->name, cb_idx));
7175 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007176 handlers++;
7177 }
7178 }
7179 /* FIXME? Examine results here? */
7180
7181 /*
7182 * If needed, send (a single) EventAck.
7183 */
7184 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307185 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007186 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007187 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307188 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007189 ioc->name, ii));
7190 }
7191 }
7192
7193 *evHandlers = handlers;
7194 return r;
7195}
7196
7197/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007198/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007199 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7200 * @ioc: Pointer to MPT_ADAPTER structure
7201 * @log_info: U32 LogInfo reply word from the IOC
7202 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007203 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007204 */
7205static void
7206mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7207{
Eric Moore7c431e52007-06-13 16:34:36 -06007208 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007209
Eric Moore7c431e52007-06-13 16:34:36 -06007210 switch (log_info & 0xFF000000) {
7211 case MPI_IOCLOGINFO_FC_INIT_BASE:
7212 desc = "FCP Initiator";
7213 break;
7214 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7215 desc = "FCP Target";
7216 break;
7217 case MPI_IOCLOGINFO_FC_LAN_BASE:
7218 desc = "LAN";
7219 break;
7220 case MPI_IOCLOGINFO_FC_MSG_BASE:
7221 desc = "MPI Message Layer";
7222 break;
7223 case MPI_IOCLOGINFO_FC_LINK_BASE:
7224 desc = "FC Link";
7225 break;
7226 case MPI_IOCLOGINFO_FC_CTX_BASE:
7227 desc = "Context Manager";
7228 break;
7229 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7230 desc = "Invalid Field Offset";
7231 break;
7232 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7233 desc = "State Change Info";
7234 break;
7235 }
7236
7237 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7238 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007239}
7240
7241/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007242/**
Moore, Eric335a9412006-01-17 17:06:23 -07007243 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007244 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007245 * @log_info: U32 LogInfo word from the IOC
7246 *
7247 * Refer to lsi/sp_log.h.
7248 */
7249static void
Moore, Eric335a9412006-01-17 17:06:23 -07007250mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007251{
7252 u32 info = log_info & 0x00FF0000;
7253 char *desc = "unknown";
7254
7255 switch (info) {
7256 case 0x00010000:
7257 desc = "bug! MID not found";
7258 if (ioc->reload_fw == 0)
7259 ioc->reload_fw++;
7260 break;
7261
7262 case 0x00020000:
7263 desc = "Parity Error";
7264 break;
7265
7266 case 0x00030000:
7267 desc = "ASYNC Outbound Overrun";
7268 break;
7269
7270 case 0x00040000:
7271 desc = "SYNC Offset Error";
7272 break;
7273
7274 case 0x00050000:
7275 desc = "BM Change";
7276 break;
7277
7278 case 0x00060000:
7279 desc = "Msg In Overflow";
7280 break;
7281
7282 case 0x00070000:
7283 desc = "DMA Error";
7284 break;
7285
7286 case 0x00080000:
7287 desc = "Outbound DMA Overrun";
7288 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007289
Linus Torvalds1da177e2005-04-16 15:20:36 -07007290 case 0x00090000:
7291 desc = "Task Management";
7292 break;
7293
7294 case 0x000A0000:
7295 desc = "Device Problem";
7296 break;
7297
7298 case 0x000B0000:
7299 desc = "Invalid Phase Change";
7300 break;
7301
7302 case 0x000C0000:
7303 desc = "Untagged Table Size";
7304 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007305
Linus Torvalds1da177e2005-04-16 15:20:36 -07007306 }
7307
7308 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7309}
7310
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007311/* strings for sas loginfo */
7312 static char *originator_str[] = {
7313 "IOP", /* 00h */
7314 "PL", /* 01h */
7315 "IR" /* 02h */
7316 };
7317 static char *iop_code_str[] = {
7318 NULL, /* 00h */
7319 "Invalid SAS Address", /* 01h */
7320 NULL, /* 02h */
7321 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007322 "Diag Message Error", /* 04h */
7323 "Task Terminated", /* 05h */
7324 "Enclosure Management", /* 06h */
7325 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007326 };
7327 static char *pl_code_str[] = {
7328 NULL, /* 00h */
7329 "Open Failure", /* 01h */
7330 "Invalid Scatter Gather List", /* 02h */
7331 "Wrong Relative Offset or Frame Length", /* 03h */
7332 "Frame Transfer Error", /* 04h */
7333 "Transmit Frame Connected Low", /* 05h */
7334 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7335 "SATA Read Log Receive Data Error", /* 07h */
7336 "SATA NCQ Fail All Commands After Error", /* 08h */
7337 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7338 "Receive Frame Invalid Message", /* 0Ah */
7339 "Receive Context Message Valid Error", /* 0Bh */
7340 "Receive Frame Current Frame Error", /* 0Ch */
7341 "SATA Link Down", /* 0Dh */
7342 "Discovery SATA Init W IOS", /* 0Eh */
7343 "Config Invalid Page", /* 0Fh */
7344 "Discovery SATA Init Timeout", /* 10h */
7345 "Reset", /* 11h */
7346 "Abort", /* 12h */
7347 "IO Not Yet Executed", /* 13h */
7348 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007349 "Persistent Reservation Out Not Affiliation "
7350 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007351 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007352 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007353 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007354 NULL, /* 19h */
7355 NULL, /* 1Ah */
7356 NULL, /* 1Bh */
7357 NULL, /* 1Ch */
7358 NULL, /* 1Dh */
7359 NULL, /* 1Eh */
7360 NULL, /* 1Fh */
7361 "Enclosure Management" /* 20h */
7362 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007363 static char *ir_code_str[] = {
7364 "Raid Action Error", /* 00h */
7365 NULL, /* 00h */
7366 NULL, /* 01h */
7367 NULL, /* 02h */
7368 NULL, /* 03h */
7369 NULL, /* 04h */
7370 NULL, /* 05h */
7371 NULL, /* 06h */
7372 NULL /* 07h */
7373 };
7374 static char *raid_sub_code_str[] = {
7375 NULL, /* 00h */
7376 "Volume Creation Failed: Data Passed too "
7377 "Large", /* 01h */
7378 "Volume Creation Failed: Duplicate Volumes "
7379 "Attempted", /* 02h */
7380 "Volume Creation Failed: Max Number "
7381 "Supported Volumes Exceeded", /* 03h */
7382 "Volume Creation Failed: DMA Error", /* 04h */
7383 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7384 "Volume Creation Failed: Error Reading "
7385 "MFG Page 4", /* 06h */
7386 "Volume Creation Failed: Creating Internal "
7387 "Structures", /* 07h */
7388 NULL, /* 08h */
7389 NULL, /* 09h */
7390 NULL, /* 0Ah */
7391 NULL, /* 0Bh */
7392 NULL, /* 0Ch */
7393 NULL, /* 0Dh */
7394 NULL, /* 0Eh */
7395 NULL, /* 0Fh */
7396 "Activation failed: Already Active Volume", /* 10h */
7397 "Activation failed: Unsupported Volume Type", /* 11h */
7398 "Activation failed: Too Many Active Volumes", /* 12h */
7399 "Activation failed: Volume ID in Use", /* 13h */
7400 "Activation failed: Reported Failure", /* 14h */
7401 "Activation failed: Importing a Volume", /* 15h */
7402 NULL, /* 16h */
7403 NULL, /* 17h */
7404 NULL, /* 18h */
7405 NULL, /* 19h */
7406 NULL, /* 1Ah */
7407 NULL, /* 1Bh */
7408 NULL, /* 1Ch */
7409 NULL, /* 1Dh */
7410 NULL, /* 1Eh */
7411 NULL, /* 1Fh */
7412 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7413 "Phys Disk failed: Data Passed too Large", /* 21h */
7414 "Phys Disk failed: DMA Error", /* 22h */
7415 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7416 "Phys Disk failed: Creating Phys Disk Config "
7417 "Page", /* 24h */
7418 NULL, /* 25h */
7419 NULL, /* 26h */
7420 NULL, /* 27h */
7421 NULL, /* 28h */
7422 NULL, /* 29h */
7423 NULL, /* 2Ah */
7424 NULL, /* 2Bh */
7425 NULL, /* 2Ch */
7426 NULL, /* 2Dh */
7427 NULL, /* 2Eh */
7428 NULL, /* 2Fh */
7429 "Compatibility Error: IR Disabled", /* 30h */
7430 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7431 "Compatibility Error: Device not Direct Access "
7432 "Device ", /* 32h */
7433 "Compatibility Error: Removable Device Found", /* 33h */
7434 "Compatibility Error: Device SCSI Version not "
7435 "2 or Higher", /* 34h */
7436 "Compatibility Error: SATA Device, 48 BIT LBA "
7437 "not Supported", /* 35h */
7438 "Compatibility Error: Device doesn't have "
7439 "512 Byte Block Sizes", /* 36h */
7440 "Compatibility Error: Volume Type Check Failed", /* 37h */
7441 "Compatibility Error: Volume Type is "
7442 "Unsupported by FW", /* 38h */
7443 "Compatibility Error: Disk Drive too Small for "
7444 "use in Volume", /* 39h */
7445 "Compatibility Error: Phys Disk for Create "
7446 "Volume not Found", /* 3Ah */
7447 "Compatibility Error: Too Many or too Few "
7448 "Disks for Volume Type", /* 3Bh */
7449 "Compatibility Error: Disk stripe Sizes "
7450 "Must be 64KB", /* 3Ch */
7451 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7452 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007453
7454/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007455/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007456 * mpt_sas_log_info - Log information returned from SAS IOC.
7457 * @ioc: Pointer to MPT_ADAPTER structure
7458 * @log_info: U32 LogInfo reply word from the IOC
7459 *
7460 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007461 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007462static void
7463mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7464{
7465union loginfo_type {
7466 u32 loginfo;
7467 struct {
7468 u32 subcode:16;
7469 u32 code:8;
7470 u32 originator:4;
7471 u32 bus_type:4;
7472 }dw;
7473};
7474 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007475 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007476 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007477 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007478
7479 sas_loginfo.loginfo = log_info;
7480 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007481 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007482 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007483
7484 originator_desc = originator_str[sas_loginfo.dw.originator];
7485
7486 switch (sas_loginfo.dw.originator) {
7487
7488 case 0: /* IOP */
7489 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007490 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007491 code_desc = iop_code_str[sas_loginfo.dw.code];
7492 break;
7493 case 1: /* PL */
7494 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007495 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007496 code_desc = pl_code_str[sas_loginfo.dw.code];
7497 break;
7498 case 2: /* IR */
7499 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007500 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007501 break;
7502 code_desc = ir_code_str[sas_loginfo.dw.code];
7503 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007504 ARRAY_SIZE(raid_sub_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007505 break;
7506 if (sas_loginfo.dw.code == 0)
7507 sub_code_desc =
7508 raid_sub_code_str[sas_loginfo.dw.subcode];
7509 break;
7510 default:
7511 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007512 }
7513
Eric Moorec6c727a2007-01-29 09:44:54 -07007514 if (sub_code_desc != NULL)
7515 printk(MYIOC_s_INFO_FMT
7516 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7517 " SubCode={%s}\n",
7518 ioc->name, log_info, originator_desc, code_desc,
7519 sub_code_desc);
7520 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007521 printk(MYIOC_s_INFO_FMT
7522 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7523 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007524 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007525 sas_loginfo.dw.subcode);
7526 else
7527 printk(MYIOC_s_INFO_FMT
7528 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7529 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007530 ioc->name, log_info, originator_desc,
7531 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007532}
7533
Linus Torvalds1da177e2005-04-16 15:20:36 -07007534/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007535/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007536 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7537 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007538 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007539 * @mf: Pointer to MPT request frame
7540 *
7541 * Refer to lsi/mpi.h.
7542 **/
7543static void
7544mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7545{
7546 Config_t *pReq = (Config_t *)mf;
7547 char extend_desc[EVENT_DESCR_STR_SZ];
7548 char *desc = NULL;
7549 u32 form;
7550 u8 page_type;
7551
7552 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7553 page_type = pReq->ExtPageType;
7554 else
7555 page_type = pReq->Header.PageType;
7556
7557 /*
7558 * ignore invalid page messages for GET_NEXT_HANDLE
7559 */
7560 form = le32_to_cpu(pReq->PageAddress);
7561 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7562 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7563 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7564 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7565 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7566 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7567 return;
7568 }
7569 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7570 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7571 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7572 return;
7573 }
7574
7575 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7576 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7577 page_type, pReq->Header.PageNumber, pReq->Action, form);
7578
7579 switch (ioc_status) {
7580
7581 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7582 desc = "Config Page Invalid Action";
7583 break;
7584
7585 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7586 desc = "Config Page Invalid Type";
7587 break;
7588
7589 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7590 desc = "Config Page Invalid Page";
7591 break;
7592
7593 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7594 desc = "Config Page Invalid Data";
7595 break;
7596
7597 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7598 desc = "Config Page No Defaults";
7599 break;
7600
7601 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7602 desc = "Config Page Can't Commit";
7603 break;
7604 }
7605
7606 if (!desc)
7607 return;
7608
Eric Moore29dd3602007-09-14 18:46:51 -06007609 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7610 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007611}
7612
7613/**
7614 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007615 * @ioc: Pointer to MPT_ADAPTER structure
7616 * @ioc_status: U32 IOCStatus word from IOC
7617 * @mf: Pointer to MPT request frame
7618 *
7619 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007620 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007621static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007622mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007623{
7624 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007625 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007626
7627 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007628
7629/****************************************************************************/
7630/* Common IOCStatus values for all replies */
7631/****************************************************************************/
7632
Linus Torvalds1da177e2005-04-16 15:20:36 -07007633 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7634 desc = "Invalid Function";
7635 break;
7636
7637 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7638 desc = "Busy";
7639 break;
7640
7641 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7642 desc = "Invalid SGL";
7643 break;
7644
7645 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7646 desc = "Internal Error";
7647 break;
7648
7649 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7650 desc = "Reserved";
7651 break;
7652
7653 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7654 desc = "Insufficient Resources";
7655 break;
7656
7657 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7658 desc = "Invalid Field";
7659 break;
7660
7661 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7662 desc = "Invalid State";
7663 break;
7664
Eric Moorec6c727a2007-01-29 09:44:54 -07007665/****************************************************************************/
7666/* Config IOCStatus values */
7667/****************************************************************************/
7668
Linus Torvalds1da177e2005-04-16 15:20:36 -07007669 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7670 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7671 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7672 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7673 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7674 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007675 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007676 break;
7677
Eric Moorec6c727a2007-01-29 09:44:54 -07007678/****************************************************************************/
7679/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7680/* */
7681/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7682/* */
7683/****************************************************************************/
7684
Linus Torvalds1da177e2005-04-16 15:20:36 -07007685 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007686 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007687 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7688 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7689 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7690 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007691 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007692 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007693 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007694 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007695 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007696 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007697 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007698 break;
7699
Eric Moorec6c727a2007-01-29 09:44:54 -07007700/****************************************************************************/
7701/* SCSI Target values */
7702/****************************************************************************/
7703
7704 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7705 desc = "Target: Priority IO";
7706 break;
7707
7708 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7709 desc = "Target: Invalid Port";
7710 break;
7711
7712 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7713 desc = "Target Invalid IO Index:";
7714 break;
7715
7716 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7717 desc = "Target: Aborted";
7718 break;
7719
7720 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7721 desc = "Target: No Conn Retryable";
7722 break;
7723
7724 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7725 desc = "Target: No Connection";
7726 break;
7727
7728 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7729 desc = "Target: Transfer Count Mismatch";
7730 break;
7731
7732 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7733 desc = "Target: STS Data not Sent";
7734 break;
7735
7736 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7737 desc = "Target: Data Offset Error";
7738 break;
7739
7740 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7741 desc = "Target: Too Much Write Data";
7742 break;
7743
7744 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7745 desc = "Target: IU Too Short";
7746 break;
7747
7748 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7749 desc = "Target: ACK NAK Timeout";
7750 break;
7751
7752 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7753 desc = "Target: Nak Received";
7754 break;
7755
7756/****************************************************************************/
7757/* Fibre Channel Direct Access values */
7758/****************************************************************************/
7759
7760 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7761 desc = "FC: Aborted";
7762 break;
7763
7764 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7765 desc = "FC: RX ID Invalid";
7766 break;
7767
7768 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7769 desc = "FC: DID Invalid";
7770 break;
7771
7772 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7773 desc = "FC: Node Logged Out";
7774 break;
7775
7776 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7777 desc = "FC: Exchange Canceled";
7778 break;
7779
7780/****************************************************************************/
7781/* LAN values */
7782/****************************************************************************/
7783
7784 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7785 desc = "LAN: Device not Found";
7786 break;
7787
7788 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7789 desc = "LAN: Device Failure";
7790 break;
7791
7792 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7793 desc = "LAN: Transmit Error";
7794 break;
7795
7796 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7797 desc = "LAN: Transmit Aborted";
7798 break;
7799
7800 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7801 desc = "LAN: Receive Error";
7802 break;
7803
7804 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7805 desc = "LAN: Receive Aborted";
7806 break;
7807
7808 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7809 desc = "LAN: Partial Packet";
7810 break;
7811
7812 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7813 desc = "LAN: Canceled";
7814 break;
7815
7816/****************************************************************************/
7817/* Serial Attached SCSI values */
7818/****************************************************************************/
7819
7820 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7821 desc = "SAS: SMP Request Failed";
7822 break;
7823
7824 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7825 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007826 break;
7827
7828 default:
7829 desc = "Others";
7830 break;
7831 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007832
7833 if (!desc)
7834 return;
7835
Eric Moore29dd3602007-09-14 18:46:51 -06007836 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
7837 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007838}
7839
7840/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007841EXPORT_SYMBOL(mpt_attach);
7842EXPORT_SYMBOL(mpt_detach);
7843#ifdef CONFIG_PM
7844EXPORT_SYMBOL(mpt_resume);
7845EXPORT_SYMBOL(mpt_suspend);
7846#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007847EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007848EXPORT_SYMBOL(mpt_register);
7849EXPORT_SYMBOL(mpt_deregister);
7850EXPORT_SYMBOL(mpt_event_register);
7851EXPORT_SYMBOL(mpt_event_deregister);
7852EXPORT_SYMBOL(mpt_reset_register);
7853EXPORT_SYMBOL(mpt_reset_deregister);
7854EXPORT_SYMBOL(mpt_device_driver_register);
7855EXPORT_SYMBOL(mpt_device_driver_deregister);
7856EXPORT_SYMBOL(mpt_get_msg_frame);
7857EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307858EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007859EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007860EXPORT_SYMBOL(mpt_send_handshake_request);
7861EXPORT_SYMBOL(mpt_verify_adapter);
7862EXPORT_SYMBOL(mpt_GetIocState);
7863EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007864EXPORT_SYMBOL(mpt_HardResetHandler);
7865EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007866EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007867EXPORT_SYMBOL(mpt_alloc_fw_memory);
7868EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007869EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007870EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007871
Linus Torvalds1da177e2005-04-16 15:20:36 -07007872/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007873/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007874 * fusion_init - Fusion MPT base driver initialization routine.
7875 *
7876 * Returns 0 for success, non-zero for failure.
7877 */
7878static int __init
7879fusion_init(void)
7880{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307881 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007882
7883 show_mptmod_ver(my_NAME, my_VERSION);
7884 printk(KERN_INFO COPYRIGHT "\n");
7885
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307886 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7887 MptCallbacks[cb_idx] = NULL;
7888 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7889 MptEvHandlers[cb_idx] = NULL;
7890 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007891 }
7892
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007893 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007894 * EventNotification handling.
7895 */
7896 mpt_base_index = mpt_register(mpt_base_reply, MPTBASE_DRIVER);
7897
7898 /* Register for hard reset handling callbacks.
7899 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307900 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007901
7902#ifdef CONFIG_PROC_FS
7903 (void) procmpt_create();
7904#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007905 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007906}
7907
7908/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007909/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007910 * fusion_exit - Perform driver unload cleanup.
7911 *
7912 * This routine frees all resources associated with each MPT adapter
7913 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7914 */
7915static void __exit
7916fusion_exit(void)
7917{
7918
Linus Torvalds1da177e2005-04-16 15:20:36 -07007919 mpt_reset_deregister(mpt_base_index);
7920
7921#ifdef CONFIG_PROC_FS
7922 procmpt_destroy();
7923#endif
7924}
7925
Linus Torvalds1da177e2005-04-16 15:20:36 -07007926module_init(fusion_init);
7927module_exit(fusion_exit);