blob: d67b26378a527214173f10365429125dbedc6f81 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptbase.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * This is the Fusion MPT base driver which supports multiple
4 * (SCSI + LAN) specialized protocol drivers.
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05305 * For use with LSI PCI chip/adapter(s)
6 * running LSI Fusion MPT (Message Passing Technology) firmware.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Prakash, Sathyacddc0ab2008-05-21 00:56:41 +05308 * Copyright (c) 1999-2008 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06009 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13/*
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; version 2 of the License.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 NO WARRANTY
24 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
25 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
26 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
27 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
28 solely responsible for determining the appropriateness of using and
29 distributing the Program and assumes all risks associated with its
30 exercise of rights under this Agreement, including but not limited to
31 the risks and costs of program errors, damage to or loss of data,
32 programs or equipment, and unavailability or interruption of operations.
33
34 DISCLAIMER OF LIABILITY
35 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
38 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
40 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
41 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
42
43 You should have received a copy of the GNU General Public License
44 along with this program; if not, write to the Free Software
45 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46*/
47/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/kernel.h>
50#include <linux/module.h>
51#include <linux/errno.h>
52#include <linux/init.h>
53#include <linux/slab.h>
54#include <linux/types.h>
55#include <linux/pci.h>
56#include <linux/kdev_t.h>
57#include <linux/blkdev.h>
58#include <linux/delay.h>
59#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040060#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <asm/io.h>
62#ifdef CONFIG_MTRR
63#include <asm/mtrr.h>
64#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#include "mptbase.h"
Eric Moore7c431e52007-06-13 16:34:36 -060067#include "lsi/mpi_log_fc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT base driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptbase"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/*
80 * cmd line parameters
81 */
Kashyap, Desaie3829682009-01-08 14:27:16 +053082
83static int mpt_msi_enable_spi;
84module_param(mpt_msi_enable_spi, int, 0);
85MODULE_PARM_DESC(mpt_msi_enable_spi, " Enable MSI Support for SPI \
86 controllers (default=0)");
87
88static int mpt_msi_enable_fc;
89module_param(mpt_msi_enable_fc, int, 0);
90MODULE_PARM_DESC(mpt_msi_enable_fc, " Enable MSI Support for FC \
91 controllers (default=0)");
92
93static int mpt_msi_enable_sas;
Yinghai Lu5ce78682009-02-18 11:25:32 -080094module_param(mpt_msi_enable_sas, int, 0);
Kashyap, Desaie3829682009-01-08 14:27:16 +053095MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS \
Yinghai Lu5ce78682009-02-18 11:25:32 -080096 controllers (default=0)");
Kashyap, Desaie3829682009-01-08 14:27:16 +053097
Christoph Hellwig4ddce142006-01-17 13:44:29 +000098
Eric Moore793955f2007-01-29 09:42:20 -070099static int mpt_channel_mapping;
100module_param(mpt_channel_mapping, int, 0);
101MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
102
Prakash, Sathya436ace72007-07-24 15:42:08 +0530103static int mpt_debug_level;
James Bottomleydb47c2d2007-07-28 13:40:21 -0400104static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
105module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
106 &mpt_debug_level, 0600);
Kashyap, Desaie3829682009-01-08 14:27:16 +0530107MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h \
108 - (default=0)");
109
Kashyap, Desai2f4c7822009-01-06 15:03:37 +0530110int mpt_fwfault_debug;
111EXPORT_SYMBOL(mpt_fwfault_debug);
112module_param_call(mpt_fwfault_debug, param_set_int, param_get_int,
113 &mpt_fwfault_debug, 0600);
114MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault"
115 " and halt Firmware on fault - (default=0)");
116
117
Prakash, Sathya436ace72007-07-24 15:42:08 +0530118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119#ifdef MFCNT
120static int mfcounter = 0;
121#define PRINT_MF_COUNT 20000
122#endif
123
124/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
125/*
126 * Public data...
127 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
Adrian Bunk15424922008-04-22 00:31:51 +0300129static struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
131#define WHOINIT_UNKNOWN 0xAA
132
133/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
134/*
135 * Private data...
136 */
137 /* Adapter link list */
138LIST_HEAD(ioc_list);
139 /* Callback lookup table */
140static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
141 /* Protocol driver class lookup table */
142static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
143 /* Event handler lookup table */
144static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
145 /* Reset handler lookup table */
146static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
147static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
148
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530150/*
151 * Driver Callback Index's
152 */
153static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
154static u8 last_drv_idx;
155
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
157/*
158 * Forward protos...
159 */
David Howells7d12e782006-10-05 14:55:46 +0100160static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530161static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
162 MPT_FRAME_HDR *reply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
164 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
165 int sleepFlag);
166static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
167static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
168static void mpt_adapter_disable(MPT_ADAPTER *ioc);
169static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
170
171static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
172static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
174static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
175static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
176static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
177static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb672005-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 Hellwig82ffb672005-09-09 16:25:54 +0200188int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
190static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
191static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
192static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530193static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Kashyap, Desaifd761752009-05-29 16:39:06 +0530194static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch,
195 int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb672005-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);
Kashyap, Desaifd761752009-05-29 16:39:06 +0530211static int ProcessEventNotification(MPT_ADAPTER *ioc,
212 EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700213static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700215static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600216static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700217static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700218static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
220/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221static int __init fusion_init (void);
222static void __exit fusion_exit (void);
223
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224#define CHIPREG_READ32(addr) readl_relaxed(addr)
225#define CHIPREG_READ32_dmasync(addr) readl(addr)
226#define CHIPREG_WRITE32(addr,val) writel(val, addr)
227#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
228#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
229
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600230static void
231pci_disable_io_access(struct pci_dev *pdev)
232{
233 u16 command_reg;
234
235 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
236 command_reg &= ~1;
237 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
238}
239
240static void
241pci_enable_io_access(struct pci_dev *pdev)
242{
243 u16 command_reg;
244
245 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
246 command_reg |= 1;
247 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
248}
249
James Bottomleydb47c2d2007-07-28 13:40:21 -0400250static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
251{
252 int ret = param_set_int(val, kp);
253 MPT_ADAPTER *ioc;
254
255 if (ret)
256 return ret;
257
258 list_for_each_entry(ioc, &ioc_list, list)
259 ioc->debug_level = mpt_debug_level;
260 return 0;
261}
262
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530263/**
264 * mpt_get_cb_idx - obtain cb_idx for registered driver
265 * @dclass: class driver enum
266 *
267 * Returns cb_idx, or zero means it wasn't found
268 **/
269static u8
270mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
271{
272 u8 cb_idx;
273
274 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
275 if (MptDriverClass[cb_idx] == dclass)
276 return cb_idx;
277 return 0;
278}
279
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530280/**
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530281 * mpt_is_discovery_complete - determine if discovery has completed
282 * @ioc: per adatper instance
283 *
284 * Returns 1 when discovery completed, else zero.
285 */
286static int
287mpt_is_discovery_complete(MPT_ADAPTER *ioc)
288{
289 ConfigExtendedPageHeader_t hdr;
290 CONFIGPARMS cfg;
291 SasIOUnitPage0_t *buffer;
292 dma_addr_t dma_handle;
293 int rc = 0;
294
295 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
296 memset(&cfg, 0, sizeof(CONFIGPARMS));
297 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
298 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
299 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
300 cfg.cfghdr.ehdr = &hdr;
301 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
302
303 if ((mpt_config(ioc, &cfg)))
304 goto out;
305 if (!hdr.ExtPageLength)
306 goto out;
307
308 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
309 &dma_handle);
310 if (!buffer)
311 goto out;
312
313 cfg.physAddr = dma_handle;
314 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
315
316 if ((mpt_config(ioc, &cfg)))
317 goto out_free_consistent;
318
319 if (!(buffer->PhyData[0].PortFlags &
320 MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS))
321 rc = 1;
322
323 out_free_consistent:
324 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
325 buffer, dma_handle);
326 out:
327 return rc;
328}
329
330/**
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530331 * mpt_fault_reset_work - work performed on workq after ioc fault
332 * @work: input argument, used to derive ioc
333 *
334**/
335static void
336mpt_fault_reset_work(struct work_struct *work)
337{
338 MPT_ADAPTER *ioc =
339 container_of(work, MPT_ADAPTER, fault_reset_work.work);
340 u32 ioc_raw_state;
341 int rc;
342 unsigned long flags;
343
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530344 if (ioc->ioc_reset_in_progress || !ioc->active)
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530345 goto out;
346
347 ioc_raw_state = mpt_GetIocState(ioc, 0);
348 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
349 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700350 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530351 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700352 ioc->name, __func__);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530353 rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
354 printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700355 __func__, (rc == 0) ? "success" : "failed");
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530356 ioc_raw_state = mpt_GetIocState(ioc, 0);
357 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
358 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
359 "reset (%04xh)\n", ioc->name, ioc_raw_state &
360 MPI_DOORBELL_DATA_MASK);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530361 } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) {
362 if ((mpt_is_discovery_complete(ioc))) {
363 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing "
364 "discovery_quiesce_io flag\n", ioc->name));
365 ioc->sas_discovery_quiesce_io = 0;
366 }
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530367 }
368
369 out:
370 /*
371 * Take turns polling alternate controller
372 */
373 if (ioc->alt_ioc)
374 ioc = ioc->alt_ioc;
375
376 /* rearm the timer */
377 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
378 if (ioc->reset_work_q)
379 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
380 msecs_to_jiffies(MPT_POLLING_INTERVAL));
381 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
382}
383
384
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600385/*
386 * Process turbo (context) reply...
387 */
388static void
389mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
390{
391 MPT_FRAME_HDR *mf = NULL;
392 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530393 u16 req_idx = 0;
394 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600395
Prakash, Sathya436ace72007-07-24 15:42:08 +0530396 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600397 ioc->name, pa));
398
399 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
400 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
401 req_idx = pa & 0x0000FFFF;
402 cb_idx = (pa & 0x00FF0000) >> 16;
403 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
404 break;
405 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530406 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600407 /*
408 * Blind set of mf to NULL here was fatal
409 * after lan_reply says "freeme"
410 * Fix sort of combined with an optimization here;
411 * added explicit check for case where lan_reply
412 * was just returning 1 and doing nothing else.
413 * For this case skip the callback, but set up
414 * proper mf value first here:-)
415 */
416 if ((pa & 0x58000000) == 0x58000000) {
417 req_idx = pa & 0x0000FFFF;
418 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
419 mpt_free_msg_frame(ioc, mf);
420 mb();
421 return;
422 break;
423 }
424 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
425 break;
426 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530427 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600428 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
429 break;
430 default:
431 cb_idx = 0;
432 BUG();
433 }
434
435 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530436 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600437 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600438 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700439 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600440 goto out;
441 }
442
443 if (MptCallbacks[cb_idx](ioc, mf, mr))
444 mpt_free_msg_frame(ioc, mf);
445 out:
446 mb();
447}
448
449static void
450mpt_reply(MPT_ADAPTER *ioc, u32 pa)
451{
452 MPT_FRAME_HDR *mf;
453 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530454 u16 req_idx;
455 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600456 int freeme;
457
458 u32 reply_dma_low;
459 u16 ioc_stat;
460
461 /* non-TURBO reply! Hmmm, something may be up...
462 * Newest turbo reply mechanism; get address
463 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
464 */
465
466 /* Map DMA address of reply header to cpu address.
467 * pa is 32 bits - but the dma address may be 32 or 64 bits
468 * get offset based only only the low addresses
469 */
470
471 reply_dma_low = (pa <<= 1);
472 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
473 (reply_dma_low - ioc->reply_frames_low_dma));
474
475 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
476 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
477 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
478
Prakash, Sathya436ace72007-07-24 15:42:08 +0530479 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 -0600480 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600481 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600482
483 /* Check/log IOC log info
484 */
485 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
486 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
487 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
488 if (ioc->bus_type == FC)
489 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700490 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700491 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600492 else if (ioc->bus_type == SAS)
493 mpt_sas_log_info(ioc, log_info);
494 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600495
Eric Moorec6c727a2007-01-29 09:44:54 -0700496 if (ioc_stat & MPI_IOCSTATUS_MASK)
497 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600498
499 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530500 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600501 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600502 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700503 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600504 freeme = 0;
505 goto out;
506 }
507
508 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
509
510 out:
511 /* Flush (non-TURBO) reply with a WRITE! */
512 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
513
514 if (freeme)
515 mpt_free_msg_frame(ioc, mf);
516 mb();
517}
518
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800520/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
522 * @irq: irq number (not used)
523 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 *
525 * This routine is registered via the request_irq() kernel API call,
526 * and handles all interrupts generated from a specific MPT adapter
527 * (also referred to as a IO Controller or IOC).
528 * This routine must clear the interrupt from the adapter and does
529 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200530 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 *
532 * This routine handles register-level access of the adapter but
533 * dispatches (calls) a protocol-specific callback routine to handle
534 * the protocol-specific details of the MPT request completion.
535 */
536static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100537mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600539 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600540 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
541
542 if (pa == 0xFFFFFFFF)
543 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
545 /*
546 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600548 do {
549 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600550 mpt_reply(ioc, pa);
551 else
552 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600553 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
554 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
556 return IRQ_HANDLED;
557}
558
559/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800560/**
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530561 * mptbase_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 * @ioc: Pointer to MPT_ADAPTER structure
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530563 * @req: Pointer to original MPT request frame
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
565 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800566 * MPT base driver's callback routine; all base driver
567 * "internal" request/reply processing is routed here.
568 * Currently used for EventNotification and EventAck handling.
569 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200570 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 * should be freed, or 0 if it shouldn't.
572 */
573static int
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530574mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530576 EventNotificationReply_t *pEventReply;
577 u8 event;
578 int evHandlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 int freereq = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530581 switch (reply->u.hdr.Function) {
582 case MPI_FUNCTION_EVENT_NOTIFICATION:
583 pEventReply = (EventNotificationReply_t *)reply;
584 evHandlers = 0;
585 ProcessEventNotification(ioc, pEventReply, &evHandlers);
586 event = le32_to_cpu(pEventReply->Event) & 0xFF;
587 if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 freereq = 0;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530589 if (event != MPI_EVENT_EVENT_CHANGE)
590 break;
591 case MPI_FUNCTION_CONFIG:
592 case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
593 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
594 if (reply) {
595 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
596 memcpy(ioc->mptbase_cmds.reply, reply,
597 min(MPT_DEFAULT_FRAME_SIZE,
598 4 * reply->u.reply.MsgLength));
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200599 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530600 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
601 ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
602 complete(&ioc->mptbase_cmds.done);
603 } else
604 freereq = 0;
605 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF)
606 freereq = 1;
607 break;
608 case MPI_FUNCTION_EVENT_ACK:
609 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
610 "EventAck reply received\n", ioc->name));
611 break;
612 default:
613 printk(MYIOC_s_ERR_FMT
614 "Unexpected msg function (=%02Xh) reply received!\n",
615 ioc->name, reply->u.hdr.Function);
616 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
618
619 /*
620 * Conditionally tell caller to free the original
621 * EventNotification/EventAck/unexpected request frame!
622 */
623 return freereq;
624}
625
626/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
627/**
628 * mpt_register - Register protocol-specific main callback handler.
629 * @cbfunc: callback function pointer
630 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
631 *
632 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800633 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 * protocol-specific driver must do this before it will be able to
635 * use any IOC resources, such as obtaining request frames.
636 *
637 * NOTES: The SCSI protocol driver currently calls this routine thrice
638 * in order to register separate callbacks; one for "normal" SCSI IO;
639 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
640 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530641 * Returns u8 valued "handle" in the range (and S.O.D. order)
642 * {N,...,7,6,5,...,1} if successful.
643 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
644 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530646u8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
648{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530649 u8 cb_idx;
650 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
652 /*
653 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
654 * (slot/handle 0 is reserved!)
655 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530656 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
657 if (MptCallbacks[cb_idx] == NULL) {
658 MptCallbacks[cb_idx] = cbfunc;
659 MptDriverClass[cb_idx] = dclass;
660 MptEvHandlers[cb_idx] = NULL;
661 last_drv_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 break;
663 }
664 }
665
666 return last_drv_idx;
667}
668
669/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
670/**
671 * mpt_deregister - Deregister a protocol drivers resources.
672 * @cb_idx: previously registered callback handle
673 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800674 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 * module is unloaded.
676 */
677void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530678mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600680 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 MptCallbacks[cb_idx] = NULL;
682 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
683 MptEvHandlers[cb_idx] = NULL;
684
685 last_drv_idx++;
686 }
687}
688
689/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
690/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800691 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 * @cb_idx: previously registered (via mpt_register) callback handle
693 * @ev_cbfunc: callback function
694 *
695 * This routine can be called by one or more protocol-specific drivers
696 * if/when they choose to be notified of MPT events.
697 *
698 * Returns 0 for success.
699 */
700int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530701mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600703 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 return -1;
705
706 MptEvHandlers[cb_idx] = ev_cbfunc;
707 return 0;
708}
709
710/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
711/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800712 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 * @cb_idx: previously registered callback handle
714 *
715 * Each protocol-specific driver should call this routine
716 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800717 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 */
719void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530720mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600722 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 return;
724
725 MptEvHandlers[cb_idx] = NULL;
726}
727
728/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
729/**
730 * mpt_reset_register - Register protocol-specific IOC reset handler.
731 * @cb_idx: previously registered (via mpt_register) callback handle
732 * @reset_func: reset function
733 *
734 * This routine can be called by one or more protocol-specific drivers
735 * if/when they choose to be notified of IOC resets.
736 *
737 * Returns 0 for success.
738 */
739int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530740mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530742 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 return -1;
744
745 MptResetHandlers[cb_idx] = reset_func;
746 return 0;
747}
748
749/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
750/**
751 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
752 * @cb_idx: previously registered callback handle
753 *
754 * Each protocol-specific driver should call this routine
755 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800756 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 */
758void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530759mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530761 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return;
763
764 MptResetHandlers[cb_idx] = NULL;
765}
766
767/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
768/**
769 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800770 * @dd_cbfunc: driver callbacks struct
771 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 */
773int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530774mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
776 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600777 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Eric Moore8d6d83e2007-09-14 18:47:40 -0600779 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400780 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
782 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
783
784 /* call per pci device probe entry point */
785 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600786 id = ioc->pcidev->driver ?
787 ioc->pcidev->driver->id_table : NULL;
788 if (dd_cbfunc->probe)
789 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 }
791
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400792 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793}
794
795/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
796/**
797 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800798 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 */
800void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530801mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802{
803 struct mpt_pci_driver *dd_cbfunc;
804 MPT_ADAPTER *ioc;
805
Eric Moore8d6d83e2007-09-14 18:47:40 -0600806 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 return;
808
809 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
810
811 list_for_each_entry(ioc, &ioc_list, list) {
812 if (dd_cbfunc->remove)
813 dd_cbfunc->remove(ioc->pcidev);
814 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200815
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 MptDeviceDriverHandlers[cb_idx] = NULL;
817}
818
819
820/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
821/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800822 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530823 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 * @ioc: Pointer to MPT adapter structure
825 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800826 * Obtain an MPT request frame from the pool (of 1024) that are
827 * allocated per MPT adapter.
828 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 * Returns pointer to a MPT request frame or %NULL if none are available
830 * or IOC is not active.
831 */
832MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530833mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834{
835 MPT_FRAME_HDR *mf;
836 unsigned long flags;
837 u16 req_idx; /* Request index */
838
839 /* validate handle and ioc identifier */
840
841#ifdef MFCNT
842 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600843 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
844 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845#endif
846
847 /* If interrupts are not attached, do not return a request frame */
848 if (!ioc->active)
849 return NULL;
850
851 spin_lock_irqsave(&ioc->FreeQlock, flags);
852 if (!list_empty(&ioc->FreeQ)) {
853 int req_offset;
854
855 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
856 u.frame.linkage.list);
857 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200858 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530859 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
861 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500862 req_idx = req_offset / ioc->req_sz;
863 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600865 /* Default, will be changed if necessary in SG generation */
866 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867#ifdef MFCNT
868 ioc->mfcnt++;
869#endif
870 }
871 else
872 mf = NULL;
873 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
874
875#ifdef MFCNT
876 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600877 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
878 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
879 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 mfcounter++;
881 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600882 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
883 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884#endif
885
Eric Moore29dd3602007-09-14 18:46:51 -0600886 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
887 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 return mf;
889}
890
891/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
892/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800893 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530894 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 * @ioc: Pointer to MPT adapter structure
896 * @mf: Pointer to MPT request frame
897 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800898 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 * specific MPT adapter.
900 */
901void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530902mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903{
904 u32 mf_dma_addr;
905 int req_offset;
906 u16 req_idx; /* Request index */
907
908 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530909 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
911 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500912 req_idx = req_offset / ioc->req_sz;
913 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
915
Prakash, Sathya436ace72007-07-24 15:42:08 +0530916 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200918 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600919 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
920 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
921 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
923}
924
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530925/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800926 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530927 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530928 * @ioc: Pointer to MPT adapter structure
929 * @mf: Pointer to MPT request frame
930 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800931 * Send a protocol-specific MPT request frame to an IOC using
932 * hi-priority request queue.
933 *
934 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530935 * specific MPT adapter.
936 **/
937void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530938mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530939{
940 u32 mf_dma_addr;
941 int req_offset;
942 u16 req_idx; /* Request index */
943
944 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530945 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530946 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
947 req_idx = req_offset / ioc->req_sz;
948 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
949 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
950
951 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
952
953 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
954 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
955 ioc->name, mf_dma_addr, req_idx));
956 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
957}
958
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
960/**
961 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 * @ioc: Pointer to MPT adapter structure
963 * @mf: Pointer to MPT request frame
964 *
965 * This routine places a MPT request frame back on the MPT adapter's
966 * FreeQ.
967 */
968void
969mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
970{
971 unsigned long flags;
972
973 /* Put Request back on FreeQ! */
974 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb672005-09-09 16:25:54 +0200975 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
977#ifdef MFCNT
978 ioc->mfcnt--;
979#endif
980 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
981}
982
983/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
984/**
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530985 * mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 * @pAddr: virtual address for SGE
987 * @flagslength: SGE flags and data transfer length
988 * @dma_addr: Physical address
989 *
990 * This routine places a MPT request frame back on the MPT adapter's
991 * FreeQ.
992 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530993static void
994mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995{
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530996 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
997 pSge->FlagsLength = cpu_to_le32(flagslength);
998 pSge->Address = cpu_to_le32(dma_addr);
999}
1000
1001/**
1002 * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
1003 * @pAddr: virtual address for SGE
1004 * @flagslength: SGE flags and data transfer length
1005 * @dma_addr: Physical address
1006 *
1007 * This routine places a MPT request frame back on the MPT adapter's
1008 * FreeQ.
1009 **/
1010static void
1011mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1012{
1013 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1014 pSge->Address.Low = cpu_to_le32
1015 (lower_32_bits((unsigned long)(dma_addr)));
1016 pSge->Address.High = cpu_to_le32
1017 (upper_32_bits((unsigned long)dma_addr));
1018 pSge->FlagsLength = cpu_to_le32
1019 ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1020}
1021
1022/**
1023 * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr
1024 * (1078 workaround).
1025 * @pAddr: virtual address for SGE
1026 * @flagslength: SGE flags and data transfer length
1027 * @dma_addr: Physical address
1028 *
1029 * This routine places a MPT request frame back on the MPT adapter's
1030 * FreeQ.
1031 **/
1032static void
1033mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1034{
1035 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1036 u32 tmp;
1037
1038 pSge->Address.Low = cpu_to_le32
1039 (lower_32_bits((unsigned long)(dma_addr)));
1040 tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
1041
1042 /*
1043 * 1078 errata workaround for the 36GB limitation
1044 */
1045 if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {
1046 flagslength |=
1047 MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
1048 tmp |= (1<<31);
1049 if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
1050 printk(KERN_DEBUG "1078 P0M2 addressing for "
1051 "addr = 0x%llx len = %d\n",
1052 (unsigned long long)dma_addr,
1053 MPI_SGE_LENGTH(flagslength));
1054 }
1055
1056 pSge->Address.High = cpu_to_le32(tmp);
1057 pSge->FlagsLength = cpu_to_le32(
1058 (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1059}
1060
1061/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1062/**
1063 * mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
1064 * @pAddr: virtual address for SGE
1065 * @next: nextChainOffset value (u32's)
1066 * @length: length of next SGL segment
1067 * @dma_addr: Physical address
1068 *
1069 */
1070static void
1071mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1072{
1073 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
1074 pChain->Length = cpu_to_le16(length);
1075 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
1076 pChain->NextChainOffset = next;
1077 pChain->Address = cpu_to_le32(dma_addr);
1078}
1079
1080/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1081/**
1082 * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
1083 * @pAddr: virtual address for SGE
1084 * @next: nextChainOffset value (u32's)
1085 * @length: length of next SGL segment
1086 * @dma_addr: Physical address
1087 *
1088 */
1089static void
1090mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1091{
1092 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 u32 tmp = dma_addr & 0xFFFFFFFF;
1094
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301095 pChain->Length = cpu_to_le16(length);
1096 pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
1097 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301099 pChain->NextChainOffset = next;
1100
1101 pChain->Address.Low = cpu_to_le32(tmp);
1102 tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
1103 pChain->Address.High = cpu_to_le32(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104}
1105
1106/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1107/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001108 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301109 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 * @ioc: Pointer to MPT adapter structure
1111 * @reqBytes: Size of the request in bytes
1112 * @req: Pointer to MPT request frame
1113 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1114 *
1115 * This routine is used exclusively to send MptScsiTaskMgmt
1116 * requests since they are required to be sent via doorbell handshake.
1117 *
1118 * NOTE: It is the callers responsibility to byte-swap fields in the
1119 * request which are greater than 1 byte in size.
1120 *
1121 * Returns 0 for success, non-zero for failure.
1122 */
1123int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301124mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125{
Eric Moorecd2c6192007-01-29 09:47:47 -07001126 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 u8 *req_as_bytes;
1128 int ii;
1129
1130 /* State is known to be good upon entering
1131 * this function so issue the bus reset
1132 * request.
1133 */
1134
1135 /*
1136 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1137 * setting cb_idx/req_idx. But ONLY if this request
1138 * is in proper (pre-alloc'd) request buffer range...
1139 */
1140 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1141 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1142 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1143 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301144 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 }
1146
1147 /* Make sure there are no doorbells */
1148 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001149
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1151 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1152 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1153
1154 /* Wait for IOC doorbell int */
1155 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1156 return ii;
1157 }
1158
1159 /* Read doorbell and check for active bit */
1160 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1161 return -5;
1162
Eric Moore29dd3602007-09-14 18:46:51 -06001163 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001164 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
1166 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1167
1168 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1169 return -2;
1170 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001171
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 /* Send request via doorbell handshake */
1173 req_as_bytes = (u8 *) req;
1174 for (ii = 0; ii < reqBytes/4; ii++) {
1175 u32 word;
1176
1177 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1178 (req_as_bytes[(ii*4) + 1] << 8) |
1179 (req_as_bytes[(ii*4) + 2] << 16) |
1180 (req_as_bytes[(ii*4) + 3] << 24));
1181 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1182 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1183 r = -3;
1184 break;
1185 }
1186 }
1187
1188 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1189 r = 0;
1190 else
1191 r = -4;
1192
1193 /* Make sure there are no doorbells */
1194 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001195
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 return r;
1197}
1198
1199/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1200/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001201 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001202 * @ioc: Pointer to MPT adapter structure
1203 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001204 * @sleepFlag: Specifies whether the process can sleep
1205 *
1206 * Provides mechanism for the host driver to control the IOC's
1207 * Host Page Buffer access.
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001208 *
1209 * Access Control Value - bits[15:12]
1210 * 0h Reserved
1211 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1212 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1213 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1214 *
1215 * Returns 0 for success, non-zero for failure.
1216 */
1217
1218static int
1219mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1220{
1221 int r = 0;
1222
1223 /* return if in use */
1224 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1225 & MPI_DOORBELL_ACTIVE)
1226 return -1;
1227
1228 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1229
1230 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1231 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1232 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1233 (access_control_value<<12)));
1234
1235 /* Wait for IOC to clear Doorbell Status bit */
1236 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1237 return -2;
1238 }else
1239 return 0;
1240}
1241
1242/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1243/**
1244 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001245 * @ioc: Pointer to pointer to IOC adapter
1246 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001247 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001248 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001249 * Returns 0 for success, non-zero for failure.
1250 */
1251static int
1252mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1253{
1254 char *psge;
1255 int flags_length;
1256 u32 host_page_buffer_sz=0;
1257
1258 if(!ioc->HostPageBuffer) {
1259
1260 host_page_buffer_sz =
1261 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1262
1263 if(!host_page_buffer_sz)
1264 return 0; /* fw doesn't need any host buffers */
1265
1266 /* spin till we get enough memory */
1267 while(host_page_buffer_sz > 0) {
1268
1269 if((ioc->HostPageBuffer = pci_alloc_consistent(
1270 ioc->pcidev,
1271 host_page_buffer_sz,
1272 &ioc->HostPageBuffer_dma)) != NULL) {
1273
Prakash, Sathya436ace72007-07-24 15:42:08 +05301274 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001275 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001276 ioc->name, ioc->HostPageBuffer,
1277 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001278 host_page_buffer_sz));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001279 ioc->alloc_total += host_page_buffer_sz;
1280 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1281 break;
1282 }
1283
1284 host_page_buffer_sz -= (4*1024);
1285 }
1286 }
1287
1288 if(!ioc->HostPageBuffer) {
1289 printk(MYIOC_s_ERR_FMT
1290 "Failed to alloc memory for host_page_buffer!\n",
1291 ioc->name);
1292 return -999;
1293 }
1294
1295 psge = (char *)&ioc_init->HostPageBufferSGE;
1296 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1297 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1298 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1299 MPI_SGE_FLAGS_HOST_TO_IOC |
1300 MPI_SGE_FLAGS_END_OF_BUFFER;
1301 if (sizeof(dma_addr_t) == sizeof(u64)) {
1302 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1303 }
1304 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1305 flags_length |= ioc->HostPageBuffer_sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301306 ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001307 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1308
1309return 0;
1310}
1311
1312/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1313/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001314 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 * @iocid: IOC unique identifier (integer)
1316 * @iocpp: Pointer to pointer to IOC adapter
1317 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001318 * Given a unique IOC identifier, set pointer to the associated MPT
1319 * adapter structure.
1320 *
1321 * Returns iocid and sets iocpp if iocid is found.
1322 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 */
1324int
1325mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1326{
1327 MPT_ADAPTER *ioc;
1328
1329 list_for_each_entry(ioc,&ioc_list,list) {
1330 if (ioc->id == iocid) {
1331 *iocpp =ioc;
1332 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001335
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 *iocpp = NULL;
1337 return -1;
1338}
1339
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301340/**
1341 * mpt_get_product_name - returns product string
1342 * @vendor: pci vendor id
1343 * @device: pci device id
1344 * @revision: pci revision id
1345 * @prod_name: string returned
1346 *
1347 * Returns product string displayed when driver loads,
1348 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1349 *
1350 **/
1351static void
1352mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1353{
1354 char *product_str = NULL;
1355
1356 if (vendor == PCI_VENDOR_ID_BROCADE) {
1357 switch (device)
1358 {
1359 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1360 switch (revision)
1361 {
1362 case 0x00:
1363 product_str = "BRE040 A0";
1364 break;
1365 case 0x01:
1366 product_str = "BRE040 A1";
1367 break;
1368 default:
1369 product_str = "BRE040";
1370 break;
1371 }
1372 break;
1373 }
1374 goto out;
1375 }
1376
1377 switch (device)
1378 {
1379 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1380 product_str = "LSIFC909 B1";
1381 break;
1382 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1383 product_str = "LSIFC919 B0";
1384 break;
1385 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1386 product_str = "LSIFC929 B0";
1387 break;
1388 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1389 if (revision < 0x80)
1390 product_str = "LSIFC919X A0";
1391 else
1392 product_str = "LSIFC919XL A1";
1393 break;
1394 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1395 if (revision < 0x80)
1396 product_str = "LSIFC929X A0";
1397 else
1398 product_str = "LSIFC929XL A1";
1399 break;
1400 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1401 product_str = "LSIFC939X A1";
1402 break;
1403 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1404 product_str = "LSIFC949X A1";
1405 break;
1406 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1407 switch (revision)
1408 {
1409 case 0x00:
1410 product_str = "LSIFC949E A0";
1411 break;
1412 case 0x01:
1413 product_str = "LSIFC949E A1";
1414 break;
1415 default:
1416 product_str = "LSIFC949E";
1417 break;
1418 }
1419 break;
1420 case MPI_MANUFACTPAGE_DEVID_53C1030:
1421 switch (revision)
1422 {
1423 case 0x00:
1424 product_str = "LSI53C1030 A0";
1425 break;
1426 case 0x01:
1427 product_str = "LSI53C1030 B0";
1428 break;
1429 case 0x03:
1430 product_str = "LSI53C1030 B1";
1431 break;
1432 case 0x07:
1433 product_str = "LSI53C1030 B2";
1434 break;
1435 case 0x08:
1436 product_str = "LSI53C1030 C0";
1437 break;
1438 case 0x80:
1439 product_str = "LSI53C1030T A0";
1440 break;
1441 case 0x83:
1442 product_str = "LSI53C1030T A2";
1443 break;
1444 case 0x87:
1445 product_str = "LSI53C1030T A3";
1446 break;
1447 case 0xc1:
1448 product_str = "LSI53C1020A A1";
1449 break;
1450 default:
1451 product_str = "LSI53C1030";
1452 break;
1453 }
1454 break;
1455 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1456 switch (revision)
1457 {
1458 case 0x03:
1459 product_str = "LSI53C1035 A2";
1460 break;
1461 case 0x04:
1462 product_str = "LSI53C1035 B0";
1463 break;
1464 default:
1465 product_str = "LSI53C1035";
1466 break;
1467 }
1468 break;
1469 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1470 switch (revision)
1471 {
1472 case 0x00:
1473 product_str = "LSISAS1064 A1";
1474 break;
1475 case 0x01:
1476 product_str = "LSISAS1064 A2";
1477 break;
1478 case 0x02:
1479 product_str = "LSISAS1064 A3";
1480 break;
1481 case 0x03:
1482 product_str = "LSISAS1064 A4";
1483 break;
1484 default:
1485 product_str = "LSISAS1064";
1486 break;
1487 }
1488 break;
1489 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1490 switch (revision)
1491 {
1492 case 0x00:
1493 product_str = "LSISAS1064E A0";
1494 break;
1495 case 0x01:
1496 product_str = "LSISAS1064E B0";
1497 break;
1498 case 0x02:
1499 product_str = "LSISAS1064E B1";
1500 break;
1501 case 0x04:
1502 product_str = "LSISAS1064E B2";
1503 break;
1504 case 0x08:
1505 product_str = "LSISAS1064E B3";
1506 break;
1507 default:
1508 product_str = "LSISAS1064E";
1509 break;
1510 }
1511 break;
1512 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1513 switch (revision)
1514 {
1515 case 0x00:
1516 product_str = "LSISAS1068 A0";
1517 break;
1518 case 0x01:
1519 product_str = "LSISAS1068 B0";
1520 break;
1521 case 0x02:
1522 product_str = "LSISAS1068 B1";
1523 break;
1524 default:
1525 product_str = "LSISAS1068";
1526 break;
1527 }
1528 break;
1529 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1530 switch (revision)
1531 {
1532 case 0x00:
1533 product_str = "LSISAS1068E A0";
1534 break;
1535 case 0x01:
1536 product_str = "LSISAS1068E B0";
1537 break;
1538 case 0x02:
1539 product_str = "LSISAS1068E B1";
1540 break;
1541 case 0x04:
1542 product_str = "LSISAS1068E B2";
1543 break;
1544 case 0x08:
1545 product_str = "LSISAS1068E B3";
1546 break;
1547 default:
1548 product_str = "LSISAS1068E";
1549 break;
1550 }
1551 break;
1552 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1553 switch (revision)
1554 {
1555 case 0x00:
1556 product_str = "LSISAS1078 A0";
1557 break;
1558 case 0x01:
1559 product_str = "LSISAS1078 B0";
1560 break;
1561 case 0x02:
1562 product_str = "LSISAS1078 C0";
1563 break;
1564 case 0x03:
1565 product_str = "LSISAS1078 C1";
1566 break;
1567 case 0x04:
1568 product_str = "LSISAS1078 C2";
1569 break;
1570 default:
1571 product_str = "LSISAS1078";
1572 break;
1573 }
1574 break;
1575 }
1576
1577 out:
1578 if (product_str)
1579 sprintf(prod_name, "%s", product_str);
1580}
1581
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301582/**
1583 * mpt_mapresources - map in memory mapped io
1584 * @ioc: Pointer to pointer to IOC adapter
1585 *
1586 **/
1587static int
1588mpt_mapresources(MPT_ADAPTER *ioc)
1589{
1590 u8 __iomem *mem;
1591 int ii;
1592 unsigned long mem_phys;
1593 unsigned long port;
1594 u32 msize;
1595 u32 psize;
1596 u8 revision;
1597 int r = -ENODEV;
1598 struct pci_dev *pdev;
1599
1600 pdev = ioc->pcidev;
1601 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1602 if (pci_enable_device_mem(pdev)) {
1603 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1604 "failed\n", ioc->name);
1605 return r;
1606 }
1607 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1608 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1609 "MEM failed\n", ioc->name);
1610 return r;
1611 }
1612
1613 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1614
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301615 if (sizeof(dma_addr_t) > 4) {
1616 const uint64_t required_mask = dma_get_required_mask
1617 (&pdev->dev);
1618 if (required_mask > DMA_BIT_MASK(32)
1619 && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
1620 && !pci_set_consistent_dma_mask(pdev,
1621 DMA_BIT_MASK(64))) {
1622 ioc->dma_mask = DMA_BIT_MASK(64);
1623 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1624 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1625 ioc->name));
1626 } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1627 && !pci_set_consistent_dma_mask(pdev,
1628 DMA_BIT_MASK(32))) {
1629 ioc->dma_mask = DMA_BIT_MASK(32);
1630 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1631 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1632 ioc->name));
1633 } else {
1634 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1635 ioc->name, pci_name(pdev));
1636 return r;
1637 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301638 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301639 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1640 && !pci_set_consistent_dma_mask(pdev,
1641 DMA_BIT_MASK(32))) {
1642 ioc->dma_mask = DMA_BIT_MASK(32);
1643 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1644 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1645 ioc->name));
1646 } else {
1647 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1648 ioc->name, pci_name(pdev));
1649 return r;
1650 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301651 }
1652
1653 mem_phys = msize = 0;
1654 port = psize = 0;
1655 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1656 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1657 if (psize)
1658 continue;
1659 /* Get I/O space! */
1660 port = pci_resource_start(pdev, ii);
1661 psize = pci_resource_len(pdev, ii);
1662 } else {
1663 if (msize)
1664 continue;
1665 /* Get memmap */
1666 mem_phys = pci_resource_start(pdev, ii);
1667 msize = pci_resource_len(pdev, ii);
1668 }
1669 }
1670 ioc->mem_size = msize;
1671
1672 mem = NULL;
1673 /* Get logical ptr for PciMem0 space */
1674 /*mem = ioremap(mem_phys, msize);*/
1675 mem = ioremap(mem_phys, msize);
1676 if (mem == NULL) {
1677 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1678 " memory!\n", ioc->name);
1679 return -EINVAL;
1680 }
1681 ioc->memmap = mem;
1682 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n",
1683 ioc->name, mem, mem_phys));
1684
1685 ioc->mem_phys = mem_phys;
1686 ioc->chip = (SYSIF_REGS __iomem *)mem;
1687
1688 /* Save Port IO values in case we need to do downloadboot */
1689 ioc->pio_mem_phys = port;
1690 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1691
1692 return 0;
1693}
1694
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001696/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001697 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001699 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 *
1701 * This routine performs all the steps necessary to bring the IOC of
1702 * a MPT adapter to a OPERATIONAL state. This includes registering
1703 * memory regions, registering the interrupt, and allocating request
1704 * and reply memory pools.
1705 *
1706 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1707 * MPT adapter.
1708 *
1709 * Returns 0 for success, non-zero for failure.
1710 *
1711 * TODO: Add support for polled controllers
1712 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001713int
1714mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715{
1716 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301717 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 u8 revision;
1720 u8 pcixcmd;
1721 static int mpt_ids = 0;
1722#ifdef CONFIG_PROC_FS
1723 struct proc_dir_entry *dent, *ent;
1724#endif
1725
Jesper Juhl56876192007-08-10 14:50:51 -07001726 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1727 if (ioc == NULL) {
1728 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1729 return -ENOMEM;
1730 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301731
Eric Moore29dd3602007-09-14 18:46:51 -06001732 ioc->id = mpt_ids++;
1733 sprintf(ioc->name, "ioc%d", ioc->id);
Jesper Juhl56876192007-08-10 14:50:51 -07001734
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301735 /*
1736 * set initial debug level
1737 * (refer to mptdebug.h)
1738 *
1739 */
1740 ioc->debug_level = mpt_debug_level;
1741 if (mpt_debug_level)
1742 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301743
Eric Moore29dd3602007-09-14 18:46:51 -06001744 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001745
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301746 ioc->pcidev = pdev;
1747 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001748 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 return r;
1750 }
1751
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301752 /*
1753 * Setting up proper handlers for scatter gather handling
1754 */
1755 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
1756 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
1757 ioc->add_sge = &mpt_add_sge_64bit_1078;
1758 else
1759 ioc->add_sge = &mpt_add_sge_64bit;
1760 ioc->add_chain = &mpt_add_chain_64bit;
1761 ioc->sg_addr_size = 8;
1762 } else {
1763 ioc->add_sge = &mpt_add_sge;
1764 ioc->add_chain = &mpt_add_chain;
1765 ioc->sg_addr_size = 4;
1766 }
1767 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
1768
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 ioc->alloc_total = sizeof(MPT_ADAPTER);
1770 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1771 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001772
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 ioc->pcidev = pdev;
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001774 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301776 spin_lock_init(&ioc->taskmgmt_lock);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05301777 mutex_init(&ioc->internal_cmds.mutex);
1778 init_completion(&ioc->internal_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301779 mutex_init(&ioc->mptbase_cmds.mutex);
1780 init_completion(&ioc->mptbase_cmds.done);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301781 mutex_init(&ioc->taskmgmt_cmds.mutex);
1782 init_completion(&ioc->taskmgmt_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301783
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 /* Initialize the event logging.
1785 */
1786 ioc->eventTypes = 0; /* None */
1787 ioc->eventContext = 0;
1788 ioc->eventLogSize = 0;
1789 ioc->events = NULL;
1790
1791#ifdef MFCNT
1792 ioc->mfcnt = 0;
1793#endif
1794
1795 ioc->cached_fw = NULL;
1796
1797 /* Initilize SCSI Config Data structure
1798 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001799 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800
Michael Reed05e8ec12006-01-13 14:31:54 -06001801 /* Initialize the fc rport list head.
1802 */
1803 INIT_LIST_HEAD(&ioc->fc_rports);
1804
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 /* Find lookup slot. */
1806 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001807
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301808
1809 /* Initialize workqueue */
1810 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
1811 spin_lock_init(&ioc->fault_reset_work_lock);
1812
Kay Sieversaab0de22008-05-02 06:02:41 +02001813 snprintf(ioc->reset_work_q_name, sizeof(ioc->reset_work_q_name),
1814 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301815 ioc->reset_work_q =
1816 create_singlethread_workqueue(ioc->reset_work_q_name);
1817 if (!ioc->reset_work_q) {
1818 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1819 ioc->name);
1820 pci_release_selected_regions(pdev, ioc->bars);
1821 kfree(ioc);
1822 return -ENOMEM;
1823 }
1824
Eric Moore29dd3602007-09-14 18:46:51 -06001825 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1826 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301828 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1829 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1830
1831 switch (pdev->device)
1832 {
1833 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1834 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1835 ioc->errata_flag_1064 = 1;
1836 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1837 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1838 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1839 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301841 break;
1842
1843 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 /* 929X Chip Fix. Set Split transactions level
1846 * for PCIX. Set MOST bits to zero.
1847 */
1848 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1849 pcixcmd &= 0x8F;
1850 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1851 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 /* 929XL Chip Fix. Set MMRBC to 0x08.
1853 */
1854 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1855 pcixcmd |= 0x08;
1856 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1857 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301859 break;
1860
1861 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 /* 919X Chip Fix. Set Split transactions level
1863 * for PCIX. Set MOST bits to zero.
1864 */
1865 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1866 pcixcmd &= 0x8F;
1867 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001868 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301869 break;
1870
1871 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 /* 1030 Chip Fix. Disable Split transactions
1873 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1874 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 if (revision < C0_1030) {
1876 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1877 pcixcmd &= 0x8F;
1878 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1879 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301880
1881 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001882 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301883 break;
1884
1885 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1886 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02001887 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301888
1889 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1890 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1891 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001892 ioc->bus_type = SAS;
1893 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301895
Kashyap, Desaie3829682009-01-08 14:27:16 +05301896 switch (ioc->bus_type) {
1897
1898 case SAS:
1899 ioc->msi_enable = mpt_msi_enable_sas;
1900 break;
1901
1902 case SPI:
1903 ioc->msi_enable = mpt_msi_enable_spi;
1904 break;
1905
1906 case FC:
1907 ioc->msi_enable = mpt_msi_enable_fc;
1908 break;
1909
1910 default:
1911 ioc->msi_enable = 0;
1912 break;
1913 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001914 if (ioc->errata_flag_1064)
1915 pci_disable_io_access(pdev);
1916
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 spin_lock_init(&ioc->FreeQlock);
1918
1919 /* Disable all! */
1920 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1921 ioc->active = 0;
1922 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1923
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301924 /* Set IOC ptr in the pcidev's driver data. */
1925 pci_set_drvdata(ioc->pcidev, ioc);
1926
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 /* Set lookup ptr. */
1928 list_add_tail(&ioc->list, &ioc_list);
1929
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001930 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 */
1932 mpt_detect_bound_ports(ioc, pdev);
1933
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301934 INIT_LIST_HEAD(&ioc->fw_event_list);
1935 spin_lock_init(&ioc->fw_event_lock);
1936 snprintf(ioc->fw_event_q_name, 20, "mpt/%d", ioc->id);
1937 ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
1938
James Bottomleyc92f2222006-03-01 09:02:49 -06001939 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1940 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001941 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1942 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001943
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001945 if (ioc->alt_ioc)
1946 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301947 iounmap(ioc->memmap);
1948 if (r != -5)
1949 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301950
1951 destroy_workqueue(ioc->reset_work_q);
1952 ioc->reset_work_q = NULL;
1953
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 kfree(ioc);
1955 pci_set_drvdata(pdev, NULL);
1956 return r;
1957 }
1958
1959 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001960 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301961 if(MptDeviceDriverHandlers[cb_idx] &&
1962 MptDeviceDriverHandlers[cb_idx]->probe) {
1963 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 }
1965 }
1966
1967#ifdef CONFIG_PROC_FS
1968 /*
1969 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1970 */
1971 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1972 if (dent) {
1973 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1974 if (ent) {
1975 ent->read_proc = procmpt_iocinfo_read;
1976 ent->data = ioc;
1977 }
1978 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1979 if (ent) {
1980 ent->read_proc = procmpt_summary_read;
1981 ent->data = ioc;
1982 }
1983 }
1984#endif
1985
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301986 if (!ioc->alt_ioc)
1987 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1988 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1989
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 return 0;
1991}
1992
1993/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001994/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001995 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 */
1998
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001999void
2000mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001{
2002 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2003 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302004 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302005 unsigned long flags;
2006 struct workqueue_struct *wq;
2007
2008 /*
2009 * Stop polling ioc for fault condition
2010 */
2011 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
2012 wq = ioc->reset_work_q;
2013 ioc->reset_work_q = NULL;
2014 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
2015 cancel_delayed_work(&ioc->fault_reset_work);
2016 destroy_workqueue(wq);
2017
Kashyap, Desai3eb08222009-05-29 16:47:26 +05302018 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2019 wq = ioc->fw_event_q;
2020 ioc->fw_event_q = NULL;
2021 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2022 destroy_workqueue(wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023
2024 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2025 remove_proc_entry(pname, NULL);
2026 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2027 remove_proc_entry(pname, NULL);
2028 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2029 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002030
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002032 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302033 if(MptDeviceDriverHandlers[cb_idx] &&
2034 MptDeviceDriverHandlers[cb_idx]->remove) {
2035 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 }
2037 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002038
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 /* Disable interrupts! */
2040 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2041
2042 ioc->active = 0;
2043 synchronize_irq(pdev->irq);
2044
2045 /* Clear any lingering interrupt */
2046 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2047
2048 CHIPREG_READ32(&ioc->chip->IntStatus);
2049
2050 mpt_adapter_dispose(ioc);
2051
2052 pci_set_drvdata(pdev, NULL);
2053}
2054
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055/**************************************************************************
2056 * Power Management
2057 */
2058#ifdef CONFIG_PM
2059/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002060/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002061 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002062 * @pdev: Pointer to pci_dev structure
2063 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002065int
2066mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067{
2068 u32 device_state;
2069 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302071 device_state = pci_choose_state(pdev, state);
2072 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2073 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2074 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075
2076 /* put ioc into READY_STATE */
2077 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2078 printk(MYIOC_s_ERR_FMT
2079 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2080 }
2081
2082 /* disable interrupts */
2083 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2084 ioc->active = 0;
2085
2086 /* Clear any lingering interrupt */
2087 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2088
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302089 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002090 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302091 pci_disable_msi(ioc->pcidev);
2092 ioc->pci_irq = -1;
2093 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302095 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 return 0;
2098}
2099
2100/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002101/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002102 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002103 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002105int
2106mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107{
2108 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2109 u32 device_state = pdev->current_state;
2110 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302111 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002112
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302113 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2114 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2115 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302117 pci_set_power_state(pdev, PCI_D0);
2118 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302120 ioc->pcidev = pdev;
2121 err = mpt_mapresources(ioc);
2122 if (err)
2123 return err;
2124
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302125 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2126 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2127 ioc->add_sge = &mpt_add_sge_64bit_1078;
2128 else
2129 ioc->add_sge = &mpt_add_sge_64bit;
2130 ioc->add_chain = &mpt_add_chain_64bit;
2131 ioc->sg_addr_size = 8;
2132 } else {
2133
2134 ioc->add_sge = &mpt_add_sge;
2135 ioc->add_chain = &mpt_add_chain;
2136 ioc->sg_addr_size = 4;
2137 }
2138 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2139
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302140 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2141 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2142 CHIPREG_READ32(&ioc->chip->Doorbell));
2143
2144 /*
2145 * Errata workaround for SAS pci express:
2146 * Upon returning to the D0 state, the contents of the doorbell will be
2147 * stale data, and this will incorrectly signal to the host driver that
2148 * the firmware is ready to process mpt commands. The workaround is
2149 * to issue a diagnostic reset.
2150 */
2151 if (ioc->bus_type == SAS && (pdev->device ==
2152 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2153 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2154 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2155 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2156 ioc->name);
2157 goto out;
2158 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302159 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160
2161 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302162 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2163 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2164 CAN_SLEEP);
2165 if (recovery_state != 0)
2166 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2167 "error:[%x]\n", ioc->name, recovery_state);
2168 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302170 "pci-resume: success\n", ioc->name);
2171 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302173
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174}
2175#endif
2176
James Bottomley4ff42a62006-05-17 18:06:52 -05002177static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302178mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002179{
2180 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2181 ioc->bus_type != SPI) ||
2182 (MptDriverClass[index] == MPTFC_DRIVER &&
2183 ioc->bus_type != FC) ||
2184 (MptDriverClass[index] == MPTSAS_DRIVER &&
2185 ioc->bus_type != SAS))
2186 /* make sure we only call the relevant reset handler
2187 * for the bus */
2188 return 0;
2189 return (MptResetHandlers[index])(ioc, reset_phase);
2190}
2191
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002193/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2195 * @ioc: Pointer to MPT adapter structure
2196 * @reason: Event word / reason
2197 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2198 *
2199 * This routine performs all the steps necessary to bring the IOC
2200 * to a OPERATIONAL state.
2201 *
2202 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2203 * MPT adapter.
2204 *
2205 * Returns:
2206 * 0 for success
2207 * -1 if failed to get board READY
2208 * -2 if READY but IOCFacts Failed
2209 * -3 if READY but PrimeIOCFifos Failed
2210 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302211 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302212 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 */
2214static int
2215mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2216{
2217 int hard_reset_done = 0;
2218 int alt_ioc_ready = 0;
2219 int hard;
2220 int rc=0;
2221 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302222 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 int handlers;
2224 int ret = 0;
2225 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002226 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302227 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228
Eric Moore29dd3602007-09-14 18:46:51 -06002229 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2230 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231
2232 /* Disable reply interrupts (also blocks FreeQ) */
2233 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2234 ioc->active = 0;
2235
2236 if (ioc->alt_ioc) {
2237 if (ioc->alt_ioc->active)
2238 reset_alt_ioc_active = 1;
2239
2240 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
2241 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
2242 ioc->alt_ioc->active = 0;
2243 }
2244
2245 hard = 1;
2246 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2247 hard = 0;
2248
2249 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2250 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002251 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2252 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253
2254 if (reset_alt_ioc_active && ioc->alt_ioc) {
2255 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002256 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2257 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002258 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 ioc->alt_ioc->active = 1;
2260 }
2261
2262 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002263 printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 }
2265 return -1;
2266 }
2267
2268 /* hard_reset_done = 0 if a soft reset was performed
2269 * and 1 if a hard reset was performed.
2270 */
2271 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2272 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2273 alt_ioc_ready = 1;
2274 else
Eric Moore29dd3602007-09-14 18:46:51 -06002275 printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 }
2277
2278 for (ii=0; ii<5; ii++) {
2279 /* Get IOC facts! Allow 5 retries */
2280 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2281 break;
2282 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002283
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284
2285 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002286 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2287 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 ret = -2;
2289 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2290 MptDisplayIocCapabilities(ioc);
2291 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002292
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 if (alt_ioc_ready) {
2294 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302295 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002296 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 /* Retry - alt IOC was initialized once
2298 */
2299 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2300 }
2301 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302302 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002303 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 alt_ioc_ready = 0;
2305 reset_alt_ioc_active = 0;
2306 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2307 MptDisplayIocCapabilities(ioc->alt_ioc);
2308 }
2309 }
2310
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302311 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2312 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2313 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2314 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2315 IORESOURCE_IO);
2316 if (pci_enable_device(ioc->pcidev))
2317 return -5;
2318 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2319 "mpt"))
2320 return -5;
2321 }
2322
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002323 /*
2324 * Device is reset now. It must have de-asserted the interrupt line
2325 * (if it was asserted) and it should be safe to register for the
2326 * interrupt now.
2327 */
2328 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2329 ioc->pci_irq = -1;
2330 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302331 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002332 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002333 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302334 else
2335 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002336 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002337 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002338 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002339 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Eric Moore29dd3602007-09-14 18:46:51 -06002340 "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302341 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002342 pci_disable_msi(ioc->pcidev);
2343 return -EBUSY;
2344 }
2345 irq_allocated = 1;
2346 ioc->pci_irq = ioc->pcidev->irq;
2347 pci_set_master(ioc->pcidev); /* ?? */
Eric Moore29dd3602007-09-14 18:46:51 -06002348 dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
2349 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002350 }
2351 }
2352
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 /* Prime reply & request queues!
2354 * (mucho alloc's) Must be done prior to
2355 * init as upper addresses are needed for init.
2356 * If fails, continue with alt-ioc processing
2357 */
2358 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2359 ret = -3;
2360
2361 /* May need to check/upload firmware & data here!
2362 * If fails, continue with alt-ioc processing
2363 */
2364 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2365 ret = -4;
2366// NEW!
2367 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002368 printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
2369 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 alt_ioc_ready = 0;
2371 reset_alt_ioc_active = 0;
2372 }
2373
2374 if (alt_ioc_ready) {
2375 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2376 alt_ioc_ready = 0;
2377 reset_alt_ioc_active = 0;
Eric Moore29dd3602007-09-14 18:46:51 -06002378 printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
2379 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 }
2381 }
2382
2383 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2384 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302385 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002386 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387
2388 /* Controller is not operational, cannot do upload
2389 */
2390 if (ret == 0) {
2391 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002392 if (rc == 0) {
2393 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2394 /*
2395 * Maintain only one pointer to FW memory
2396 * so there will not be two attempt to
2397 * downloadboot onboard dual function
2398 * chips (mpt_adapter_disable,
2399 * mpt_diag_reset)
2400 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302401 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002402 "mpt_upload: alt_%s has cached_fw=%p \n",
2403 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302404 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002405 }
2406 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002407 printk(MYIOC_s_WARN_FMT
2408 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302409 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002410 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 }
2412 }
2413 }
2414
Kashyap, Desaifd761752009-05-29 16:39:06 +05302415 /* Enable MPT base driver management of EventNotification
2416 * and EventAck handling.
2417 */
2418 if ((ret == 0) && (!ioc->facts.EventState)) {
2419 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2420 "SendEventNotification\n",
2421 ioc->name));
2422 ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
2423 }
2424
2425 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2426 rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
2427
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 if (ret == 0) {
2429 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002430 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 ioc->active = 1;
2432 }
Kashyap, Desaifd761752009-05-29 16:39:06 +05302433 if (rc == 0) { /* alt ioc */
2434 if (reset_alt_ioc_active && ioc->alt_ioc) {
2435 /* (re)Enable alt-IOC! (reply interrupt) */
2436 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
2437 "reply irq re-enabled\n",
2438 ioc->alt_ioc->name));
2439 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2440 MPI_HIM_DIM);
2441 ioc->alt_ioc->active = 1;
2442 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 }
2444
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002446 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2448 * recursive scenario; GetLanConfigPages times out, timer expired
2449 * routine calls HardResetHandler, which calls into here again,
2450 * and we try GetLanConfigPages again...
2451 */
2452 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002453
2454 /*
2455 * Initalize link list for inactive raid volumes.
2456 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002457 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002458 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2459
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002460 if (ioc->bus_type == SAS) {
2461
2462 /* clear persistency table */
2463 if(ioc->facts.IOCExceptions &
2464 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2465 ret = mptbase_sas_persist_operation(ioc,
2466 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2467 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002468 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002469 }
2470
2471 /* Find IM volumes
2472 */
2473 mpt_findImVolumes(ioc);
2474
2475 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2477 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2478 /*
2479 * Pre-fetch the ports LAN MAC address!
2480 * (LANPage1_t stuff)
2481 */
2482 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302483 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2484 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002485 "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2486 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302487
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 }
2489 } else {
2490 /* Get NVRAM and adapter maximums from SPP 0 and 2
2491 */
2492 mpt_GetScsiPortSettings(ioc, 0);
2493
2494 /* Get version and length of SDP 1
2495 */
2496 mpt_readScsiDevicePageHeaders(ioc, 0);
2497
2498 /* Find IM volumes
2499 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002500 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 mpt_findImVolumes(ioc);
2502
2503 /* Check, and possibly reset, the coalescing value
2504 */
2505 mpt_read_ioc_pg_1(ioc);
2506
2507 mpt_read_ioc_pg_4(ioc);
2508 }
2509
2510 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302511 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 }
2513
2514 /*
2515 * Call each currently registered protocol IOC reset handler
2516 * with post-reset indication.
2517 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2518 * MptResetHandlers[] registered yet.
2519 */
2520 if (hard_reset_done) {
2521 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302522 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2523 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302524 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002525 "Calling IOC post_reset handler #%d\n",
2526 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302527 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 handlers++;
2529 }
2530
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302531 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302532 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002533 "Calling IOC post_reset handler #%d\n",
2534 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302535 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 handlers++;
2537 }
2538 }
2539 /* FIXME? Examine results here? */
2540 }
2541
Eric Moore0ccdb002006-07-11 17:33:13 -06002542 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002543 if ((ret != 0) && irq_allocated) {
2544 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302545 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002546 pci_disable_msi(ioc->pcidev);
2547 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 return ret;
2549}
2550
2551/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002552/**
2553 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 * @ioc: Pointer to MPT adapter structure
2555 * @pdev: Pointer to (struct pci_dev) structure
2556 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002557 * Search for PCI bus/dev_function which matches
2558 * PCI bus/dev_function (+/-1) for newly discovered 929,
2559 * 929X, 1030 or 1035.
2560 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2562 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2563 */
2564static void
2565mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2566{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002567 struct pci_dev *peer=NULL;
2568 unsigned int slot = PCI_SLOT(pdev->devfn);
2569 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 MPT_ADAPTER *ioc_srch;
2571
Prakash, Sathya436ace72007-07-24 15:42:08 +05302572 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002573 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002574 ioc->name, pci_name(pdev), pdev->bus->number,
2575 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002576
2577 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2578 if (!peer) {
2579 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2580 if (!peer)
2581 return;
2582 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583
2584 list_for_each_entry(ioc_srch, &ioc_list, list) {
2585 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002586 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 /* Paranoia checks */
2588 if (ioc->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002589 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002590 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 break;
2592 } else if (ioc_srch->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002593 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002594 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 break;
2596 }
Eric Moore29dd3602007-09-14 18:46:51 -06002597 dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002598 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 ioc_srch->alt_ioc = ioc;
2600 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 }
2602 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002603 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604}
2605
2606/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002607/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002609 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 */
2611static void
2612mpt_adapter_disable(MPT_ADAPTER *ioc)
2613{
2614 int sz;
2615 int ret;
2616
2617 if (ioc->cached_fw != NULL) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05302618 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002619 "adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302620 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2621 ioc->cached_fw, CAN_SLEEP)) < 0) {
2622 printk(MYIOC_s_WARN_FMT
2623 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002624 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 }
2626 }
2627
2628 /* Disable adapter interrupts! */
2629 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2630 ioc->active = 0;
2631 /* Clear any lingering interrupt */
2632 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2633
2634 if (ioc->alloc != NULL) {
2635 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002636 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2637 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 pci_free_consistent(ioc->pcidev, sz,
2639 ioc->alloc, ioc->alloc_dma);
2640 ioc->reply_frames = NULL;
2641 ioc->req_frames = NULL;
2642 ioc->alloc = NULL;
2643 ioc->alloc_total -= sz;
2644 }
2645
2646 if (ioc->sense_buf_pool != NULL) {
2647 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2648 pci_free_consistent(ioc->pcidev, sz,
2649 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2650 ioc->sense_buf_pool = NULL;
2651 ioc->alloc_total -= sz;
2652 }
2653
2654 if (ioc->events != NULL){
2655 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2656 kfree(ioc->events);
2657 ioc->events = NULL;
2658 ioc->alloc_total -= sz;
2659 }
2660
Prakash, Sathya984621b2008-01-11 14:42:17 +05302661 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002663 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002664 mpt_inactive_raid_list_free(ioc);
2665 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002666 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002667 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002668 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669
2670 if (ioc->spi_data.pIocPg4 != NULL) {
2671 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302672 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 ioc->spi_data.pIocPg4,
2674 ioc->spi_data.IocPg4_dma);
2675 ioc->spi_data.pIocPg4 = NULL;
2676 ioc->alloc_total -= sz;
2677 }
2678
2679 if (ioc->ReqToChain != NULL) {
2680 kfree(ioc->ReqToChain);
2681 kfree(ioc->RequestNB);
2682 ioc->ReqToChain = NULL;
2683 }
2684
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002685 kfree(ioc->ChainToChain);
2686 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002687
2688 if (ioc->HostPageBuffer != NULL) {
2689 if((ret = mpt_host_page_access_control(ioc,
2690 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002691 printk(MYIOC_s_ERR_FMT
2692 "host page buffers free failed (%d)!\n",
2693 ioc->name, ret);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002694 }
Eric Moore29dd3602007-09-14 18:46:51 -06002695 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002696 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2697 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002698 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002699 ioc->HostPageBuffer = NULL;
2700 ioc->HostPageBuffer_sz = 0;
2701 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2702 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703}
2704
2705/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002706/**
2707 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 * @ioc: Pointer to MPT adapter structure
2709 *
2710 * This routine unregisters h/w resources and frees all alloc'd memory
2711 * associated with a MPT adapter structure.
2712 */
2713static void
2714mpt_adapter_dispose(MPT_ADAPTER *ioc)
2715{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002716 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002718 if (ioc == NULL)
2719 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002721 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002723 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002725 if (ioc->pci_irq != -1) {
2726 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302727 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002728 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002729 ioc->pci_irq = -1;
2730 }
2731
2732 if (ioc->memmap != NULL) {
2733 iounmap(ioc->memmap);
2734 ioc->memmap = NULL;
2735 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302737 pci_disable_device(ioc->pcidev);
2738 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2739
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002741 if (ioc->mtrr_reg > 0) {
2742 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002743 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002744 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745#endif
2746
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002747 /* Zap the adapter lookup ptr! */
2748 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002750 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002751 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2752 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002753
2754 if (ioc->alt_ioc)
2755 ioc->alt_ioc->alt_ioc = NULL;
2756
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002757 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758}
2759
2760/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002761/**
2762 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 * @ioc: Pointer to MPT adapter structure
2764 */
2765static void
2766MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2767{
2768 int i = 0;
2769
2770 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302771 if (ioc->prod_name)
2772 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 printk("Capabilities={");
2774
2775 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2776 printk("Initiator");
2777 i++;
2778 }
2779
2780 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2781 printk("%sTarget", i ? "," : "");
2782 i++;
2783 }
2784
2785 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2786 printk("%sLAN", i ? "," : "");
2787 i++;
2788 }
2789
2790#if 0
2791 /*
2792 * This would probably evoke more questions than it's worth
2793 */
2794 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2795 printk("%sLogBusAddr", i ? "," : "");
2796 i++;
2797 }
2798#endif
2799
2800 printk("}\n");
2801}
2802
2803/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002804/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2806 * @ioc: Pointer to MPT_ADAPTER structure
2807 * @force: Force hard KickStart of IOC
2808 * @sleepFlag: Specifies whether the process can sleep
2809 *
2810 * Returns:
2811 * 1 - DIAG reset and READY
2812 * 0 - READY initially OR soft reset and READY
2813 * -1 - Any failure on KickStart
2814 * -2 - Msg Unit Reset Failed
2815 * -3 - IO Unit Reset Failed
2816 * -4 - IOC owned by a PEER
2817 */
2818static int
2819MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2820{
2821 u32 ioc_state;
2822 int statefault = 0;
2823 int cntdn;
2824 int hard_reset_done = 0;
2825 int r;
2826 int ii;
2827 int whoinit;
2828
2829 /* Get current [raw] IOC state */
2830 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002831 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832
2833 /*
2834 * Check to see if IOC got left/stuck in doorbell handshake
2835 * grip of death. If so, hard reset the IOC.
2836 */
2837 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2838 statefault = 1;
2839 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2840 ioc->name);
2841 }
2842
2843 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002844 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 return 0;
2846
2847 /*
2848 * Check to see if IOC is in FAULT state.
2849 */
2850 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2851 statefault = 2;
2852 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002853 ioc->name);
2854 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2855 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 }
2857
2858 /*
2859 * Hmmm... Did it get left operational?
2860 */
2861 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302862 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 ioc->name));
2864
2865 /* Check WhoInit.
2866 * If PCI Peer, exit.
2867 * Else, if no fault conditions are present, issue a MessageUnitReset
2868 * Else, fall through to KickStart case
2869 */
2870 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002871 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2872 "whoinit 0x%x statefault %d force %d\n",
2873 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 if (whoinit == MPI_WHOINIT_PCI_PEER)
2875 return -4;
2876 else {
2877 if ((statefault == 0 ) && (force == 0)) {
2878 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2879 return 0;
2880 }
2881 statefault = 3;
2882 }
2883 }
2884
2885 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2886 if (hard_reset_done < 0)
2887 return -1;
2888
2889 /*
2890 * Loop here waiting for IOC to come READY.
2891 */
2892 ii = 0;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02002893 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894
2895 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2896 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2897 /*
2898 * BIOS or previous driver load left IOC in OP state.
2899 * Reset messaging FIFOs.
2900 */
2901 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2902 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2903 return -2;
2904 }
2905 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2906 /*
2907 * Something is wrong. Try to get IOC back
2908 * to a known state.
2909 */
2910 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2911 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2912 return -3;
2913 }
2914 }
2915
2916 ii++; cntdn--;
2917 if (!cntdn) {
2918 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2919 ioc->name, (int)((ii+5)/HZ));
2920 return -ETIME;
2921 }
2922
2923 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002924 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 } else {
2926 mdelay (1); /* 1 msec delay */
2927 }
2928
2929 }
2930
2931 if (statefault < 3) {
2932 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2933 ioc->name,
2934 statefault==1 ? "stuck handshake" : "IOC FAULT");
2935 }
2936
2937 return hard_reset_done;
2938}
2939
2940/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002941/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 * mpt_GetIocState - Get the current state of a MPT adapter.
2943 * @ioc: Pointer to MPT_ADAPTER structure
2944 * @cooked: Request raw or cooked IOC state
2945 *
2946 * Returns all IOC Doorbell register bits if cooked==0, else just the
2947 * Doorbell bits in MPI_IOC_STATE_MASK.
2948 */
2949u32
2950mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2951{
2952 u32 s, sc;
2953
2954 /* Get! */
2955 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 sc = s & MPI_IOC_STATE_MASK;
2957
2958 /* Save! */
2959 ioc->last_state = sc;
2960
2961 return cooked ? sc : s;
2962}
2963
2964/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002965/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 * GetIocFacts - Send IOCFacts request to MPT adapter.
2967 * @ioc: Pointer to MPT_ADAPTER structure
2968 * @sleepFlag: Specifies whether the process can sleep
2969 * @reason: If recovery, only update facts.
2970 *
2971 * Returns 0 for success, non-zero for failure.
2972 */
2973static int
2974GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2975{
2976 IOCFacts_t get_facts;
2977 IOCFactsReply_t *facts;
2978 int r;
2979 int req_sz;
2980 int reply_sz;
2981 int sz;
2982 u32 status, vv;
2983 u8 shiftFactor=1;
2984
2985 /* IOC *must* NOT be in RESET state! */
2986 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002987 printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
2988 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 return -44;
2990 }
2991
2992 facts = &ioc->facts;
2993
2994 /* Destination (reply area)... */
2995 reply_sz = sizeof(*facts);
2996 memset(facts, 0, reply_sz);
2997
2998 /* Request area (get_facts on the stack right now!) */
2999 req_sz = sizeof(get_facts);
3000 memset(&get_facts, 0, req_sz);
3001
3002 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
3003 /* Assert: All other get_facts fields are zero! */
3004
Prakash, Sathya436ace72007-07-24 15:42:08 +05303005 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003006 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 ioc->name, req_sz, reply_sz));
3008
3009 /* No non-zero fields in the get_facts request are greater than
3010 * 1 byte in size, so we can just fire it off as is.
3011 */
3012 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3013 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3014 if (r != 0)
3015 return r;
3016
3017 /*
3018 * Now byte swap (GRRR) the necessary fields before any further
3019 * inspection of reply contents.
3020 *
3021 * But need to do some sanity checks on MsgLength (byte) field
3022 * to make sure we don't zero IOC's req_sz!
3023 */
3024 /* Did we get a valid reply? */
3025 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3026 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3027 /*
3028 * If not been here, done that, save off first WhoInit value
3029 */
3030 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3031 ioc->FirstWhoInit = facts->WhoInit;
3032 }
3033
3034 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3035 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3036 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3037 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3038 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003039 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040 /* CHECKME! IOCStatus, IOCLogInfo */
3041
3042 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3043 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3044
3045 /*
3046 * FC f/w version changed between 1.1 and 1.2
3047 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3048 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3049 */
3050 if (facts->MsgVersion < 0x0102) {
3051 /*
3052 * Handle old FC f/w style, convert to new...
3053 */
3054 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3055 facts->FWVersion.Word =
3056 ((oldv<<12) & 0xFF000000) |
3057 ((oldv<<8) & 0x000FFF00);
3058 } else
3059 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3060
3061 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07003062 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3063 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3064 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 facts->CurrentHostMfaHighAddr =
3066 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3067 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3068 facts->CurrentSenseBufferHighAddr =
3069 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3070 facts->CurReplyFrameSize =
3071 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003072 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073
3074 /*
3075 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3076 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3077 * to 14 in MPI-1.01.0x.
3078 */
3079 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
3080 facts->MsgVersion > 0x0100) {
3081 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3082 }
3083
3084 sz = facts->FWImageSize;
3085 if ( sz & 0x01 )
3086 sz += 1;
3087 if ( sz & 0x02 )
3088 sz += 2;
3089 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003090
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 if (!facts->RequestFrameSize) {
3092 /* Something is wrong! */
3093 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3094 ioc->name);
3095 return -55;
3096 }
3097
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003098 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 vv = ((63 / (sz * 4)) + 1) & 0x03;
3100 ioc->NB_for_64_byte_frame = vv;
3101 while ( sz )
3102 {
3103 shiftFactor++;
3104 sz = sz >> 1;
3105 }
3106 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303107 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003108 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3109 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003110
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3112 /*
3113 * Set values for this IOC's request & reply frame sizes,
3114 * and request & reply queue depths...
3115 */
3116 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3117 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3118 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3119 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3120
Prakash, Sathya436ace72007-07-24 15:42:08 +05303121 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303123 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 ioc->name, ioc->req_sz, ioc->req_depth));
3125
3126 /* Get port facts! */
3127 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3128 return r;
3129 }
3130 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003131 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3133 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3134 RequestFrameSize)/sizeof(u32)));
3135 return -66;
3136 }
3137
3138 return 0;
3139}
3140
3141/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003142/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 * GetPortFacts - Send PortFacts request to MPT adapter.
3144 * @ioc: Pointer to MPT_ADAPTER structure
3145 * @portnum: Port number
3146 * @sleepFlag: Specifies whether the process can sleep
3147 *
3148 * Returns 0 for success, non-zero for failure.
3149 */
3150static int
3151GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3152{
3153 PortFacts_t get_pfacts;
3154 PortFactsReply_t *pfacts;
3155 int ii;
3156 int req_sz;
3157 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003158 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159
3160 /* IOC *must* NOT be in RESET state! */
3161 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003162 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3163 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 return -4;
3165 }
3166
3167 pfacts = &ioc->pfacts[portnum];
3168
3169 /* Destination (reply area)... */
3170 reply_sz = sizeof(*pfacts);
3171 memset(pfacts, 0, reply_sz);
3172
3173 /* Request area (get_pfacts on the stack right now!) */
3174 req_sz = sizeof(get_pfacts);
3175 memset(&get_pfacts, 0, req_sz);
3176
3177 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3178 get_pfacts.PortNumber = portnum;
3179 /* Assert: All other get_pfacts fields are zero! */
3180
Prakash, Sathya436ace72007-07-24 15:42:08 +05303181 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 ioc->name, portnum));
3183
3184 /* No non-zero fields in the get_pfacts request are greater than
3185 * 1 byte in size, so we can just fire it off as is.
3186 */
3187 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3188 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3189 if (ii != 0)
3190 return ii;
3191
3192 /* Did we get a valid reply? */
3193
3194 /* Now byte swap the necessary fields in the response. */
3195 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3196 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3197 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3198 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3199 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3200 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3201 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3202 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3203 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3204
Eric Moore793955f2007-01-29 09:42:20 -07003205 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3206 pfacts->MaxDevices;
3207 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3208 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3209
3210 /*
3211 * Place all the devices on channels
3212 *
3213 * (for debuging)
3214 */
3215 if (mpt_channel_mapping) {
3216 ioc->devices_per_bus = 1;
3217 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3218 }
3219
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 return 0;
3221}
3222
3223/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003224/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 * SendIocInit - Send IOCInit request to MPT adapter.
3226 * @ioc: Pointer to MPT_ADAPTER structure
3227 * @sleepFlag: Specifies whether the process can sleep
3228 *
3229 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3230 *
3231 * Returns 0 for success, non-zero for failure.
3232 */
3233static int
3234SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3235{
3236 IOCInit_t ioc_init;
3237 MPIDefaultReply_t init_reply;
3238 u32 state;
3239 int r;
3240 int count;
3241 int cntdn;
3242
3243 memset(&ioc_init, 0, sizeof(ioc_init));
3244 memset(&init_reply, 0, sizeof(init_reply));
3245
3246 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3247 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3248
3249 /* If we are in a recovery mode and we uploaded the FW image,
3250 * then this pointer is not NULL. Skip the upload a second time.
3251 * Set this flag if cached_fw set for either IOC.
3252 */
3253 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3254 ioc->upload_fw = 1;
3255 else
3256 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303257 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3259
Eric Moore793955f2007-01-29 09:42:20 -07003260 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3261 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303262 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003263 ioc->name, ioc->facts.MsgVersion));
3264 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3265 // set MsgVersion and HeaderVersion host driver was built with
3266 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3267 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003269 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3270 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3271 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3272 return -99;
3273 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3275
3276 if (sizeof(dma_addr_t) == sizeof(u64)) {
3277 /* Save the upper 32-bits of the request
3278 * (reply) and sense buffers.
3279 */
3280 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3281 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3282 } else {
3283 /* Force 32-bit addressing */
3284 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3285 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3286 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003287
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3289 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003290 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3291 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292
Prakash, Sathya436ace72007-07-24 15:42:08 +05303293 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 ioc->name, &ioc_init));
3295
3296 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3297 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003298 if (r != 0) {
3299 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300 return r;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003301 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302
3303 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003304 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 */
3306
Prakash, Sathya436ace72007-07-24 15:42:08 +05303307 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003309
3310 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3311 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314
3315 /* YIKES! SUPER IMPORTANT!!!
3316 * Poll IocState until _OPERATIONAL while IOC is doing
3317 * LoopInit and TargetDiscovery!
3318 */
3319 count = 0;
3320 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3321 state = mpt_GetIocState(ioc, 1);
3322 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3323 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003324 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 } else {
3326 mdelay(1);
3327 }
3328
3329 if (!cntdn) {
3330 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3331 ioc->name, (int)((count+5)/HZ));
3332 return -9;
3333 }
3334
3335 state = mpt_GetIocState(ioc, 1);
3336 count++;
3337 }
Eric Moore29dd3602007-09-14 18:46:51 -06003338 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 ioc->name, count));
3340
Eric Mooreba856d32006-07-11 17:34:01 -06003341 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 return r;
3343}
3344
3345/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003346/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 * SendPortEnable - Send PortEnable request to MPT adapter port.
3348 * @ioc: Pointer to MPT_ADAPTER structure
3349 * @portnum: Port number to enable
3350 * @sleepFlag: Specifies whether the process can sleep
3351 *
3352 * Send PortEnable to bring IOC to OPERATIONAL state.
3353 *
3354 * Returns 0 for success, non-zero for failure.
3355 */
3356static int
3357SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3358{
3359 PortEnable_t port_enable;
3360 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003361 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362 int req_sz;
3363 int reply_sz;
3364
3365 /* Destination... */
3366 reply_sz = sizeof(MPIDefaultReply_t);
3367 memset(&reply_buf, 0, reply_sz);
3368
3369 req_sz = sizeof(PortEnable_t);
3370 memset(&port_enable, 0, req_sz);
3371
3372 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3373 port_enable.PortNumber = portnum;
3374/* port_enable.ChainOffset = 0; */
3375/* port_enable.MsgFlags = 0; */
3376/* port_enable.MsgContext = 0; */
3377
Prakash, Sathya436ace72007-07-24 15:42:08 +05303378 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 ioc->name, portnum, &port_enable));
3380
3381 /* RAID FW may take a long time to enable
3382 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003383 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003384 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3385 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3386 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003387 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003388 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3389 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3390 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003392 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393}
3394
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003395/**
3396 * mpt_alloc_fw_memory - allocate firmware memory
3397 * @ioc: Pointer to MPT_ADAPTER structure
3398 * @size: total FW bytes
3399 *
3400 * If memory has already been allocated, the same (cached) value
3401 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303402 *
3403 * Return 0 if successfull, or non-zero for failure
3404 **/
3405int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3407{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303408 int rc;
3409
3410 if (ioc->cached_fw) {
3411 rc = 0; /* use already allocated memory */
3412 goto out;
3413 }
3414 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3416 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303417 rc = 0;
3418 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303420 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3421 if (!ioc->cached_fw) {
3422 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3423 ioc->name);
3424 rc = -1;
3425 } else {
3426 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3427 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3428 ioc->alloc_total += size;
3429 rc = 0;
3430 }
3431 out:
3432 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303434
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003435/**
3436 * mpt_free_fw_memory - free firmware memory
3437 * @ioc: Pointer to MPT_ADAPTER structure
3438 *
3439 * If alt_img is NULL, delete from ioc structure.
3440 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303441 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442void
3443mpt_free_fw_memory(MPT_ADAPTER *ioc)
3444{
3445 int sz;
3446
Prakash, Sathya984621b2008-01-11 14:42:17 +05303447 if (!ioc->cached_fw)
3448 return;
3449
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303451 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3452 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003453 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303454 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456}
3457
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003459/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3461 * @ioc: Pointer to MPT_ADAPTER structure
3462 * @sleepFlag: Specifies whether the process can sleep
3463 *
3464 * Returns 0 for success, >0 for handshake failure
3465 * <0 for fw upload failure.
3466 *
3467 * Remark: If bound IOC and a successful FWUpload was performed
3468 * on the bound IOC, the second image is discarded
3469 * and memory is free'd. Both channels must upload to prevent
3470 * IOC from running in degraded mode.
3471 */
3472static int
3473mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3474{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 u8 reply[sizeof(FWUploadReply_t)];
3476 FWUpload_t *prequest;
3477 FWUploadReply_t *preply;
3478 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 u32 flagsLength;
3480 int ii, sz, reply_sz;
3481 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303482 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 /* If the image size is 0, we are done.
3484 */
3485 if ((sz = ioc->facts.FWImageSize) == 0)
3486 return 0;
3487
Prakash, Sathya984621b2008-01-11 14:42:17 +05303488 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3489 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490
Eric Moore29dd3602007-09-14 18:46:51 -06003491 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3492 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003493
Eric Moorebc6e0892007-09-29 10:16:28 -06003494 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3495 kzalloc(ioc->req_sz, GFP_KERNEL);
3496 if (!prequest) {
3497 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3498 "while allocating memory \n", ioc->name));
3499 mpt_free_fw_memory(ioc);
3500 return -ENOMEM;
3501 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502
Eric Moorebc6e0892007-09-29 10:16:28 -06003503 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504
3505 reply_sz = sizeof(reply);
3506 memset(preply, 0, reply_sz);
3507
3508 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3509 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3510
3511 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3512 ptcsge->DetailsLength = 12;
3513 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3514 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003515 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303518 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3519 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3520 ioc->SGE_size;
3521 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3522 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3523 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003524 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303526 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3527 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528
Eric Moore29dd3602007-09-14 18:46:51 -06003529 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530
3531 cmdStatus = -EFAULT;
3532 if (ii == 0) {
3533 /* Handshake transfer was complete and successful.
3534 * Check the Reply Frame.
3535 */
3536 int status, transfer_sz;
3537 status = le16_to_cpu(preply->IOCStatus);
3538 if (status == MPI_IOCSTATUS_SUCCESS) {
3539 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3540 if (transfer_sz == sz)
3541 cmdStatus = 0;
3542 }
3543 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303544 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545 ioc->name, cmdStatus));
3546
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003547
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548 if (cmdStatus) {
3549
Prakash, Sathya436ace72007-07-24 15:42:08 +05303550 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551 ioc->name));
3552 mpt_free_fw_memory(ioc);
3553 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003554 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555
3556 return cmdStatus;
3557}
3558
3559/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003560/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561 * mpt_downloadboot - DownloadBoot code
3562 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003563 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564 * @sleepFlag: Specifies whether the process can sleep
3565 *
3566 * FwDownloadBoot requires Programmed IO access.
3567 *
3568 * Returns 0 for success
3569 * -1 FW Image size is 0
3570 * -2 No valid cached_fw Pointer
3571 * <0 for fw upload failure.
3572 */
3573static int
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003574mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576 MpiExtImageHeader_t *pExtImage;
3577 u32 fwSize;
3578 u32 diag0val;
3579 int count;
3580 u32 *ptrFw;
3581 u32 diagRwData;
3582 u32 nextImage;
3583 u32 load_addr;
3584 u32 ioc_state=0;
3585
Prakash, Sathya436ace72007-07-24 15:42:08 +05303586 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003587 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003588
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3590 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3591 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3592 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3593 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3594 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3595
3596 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3597
3598 /* wait 1 msec */
3599 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003600 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601 } else {
3602 mdelay (1);
3603 }
3604
3605 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3606 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3607
3608 for (count = 0; count < 30; count ++) {
3609 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3610 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303611 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612 ioc->name, count));
3613 break;
3614 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003615 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003617 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 } else {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003619 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 }
3621 }
3622
3623 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303624 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003625 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 ioc->name, diag0val));
3627 return -3;
3628 }
3629
3630 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3631 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3632 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3633 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3634 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3635 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3636
3637 /* Set the DiagRwEn and Disable ARM bits */
3638 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3639
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640 fwSize = (pFwHeader->ImageSize + 3)/4;
3641 ptrFw = (u32 *) pFwHeader;
3642
3643 /* Write the LoadStartAddress to the DiagRw Address Register
3644 * using Programmed IO
3645 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003646 if (ioc->errata_flag_1064)
3647 pci_enable_io_access(ioc->pcidev);
3648
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303650 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 ioc->name, pFwHeader->LoadStartAddress));
3652
Prakash, Sathya436ace72007-07-24 15:42:08 +05303653 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 ioc->name, fwSize*4, ptrFw));
3655 while (fwSize--) {
3656 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3657 }
3658
3659 nextImage = pFwHeader->NextImageHeaderOffset;
3660 while (nextImage) {
3661 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3662
3663 load_addr = pExtImage->LoadStartAddress;
3664
3665 fwSize = (pExtImage->ImageSize + 3) >> 2;
3666 ptrFw = (u32 *)pExtImage;
3667
Prakash, Sathya436ace72007-07-24 15:42:08 +05303668 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 +02003669 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3671
3672 while (fwSize--) {
3673 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3674 }
3675 nextImage = pExtImage->NextImageHeaderOffset;
3676 }
3677
3678 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303679 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3681
3682 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303683 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3685
3686 /* Clear the internal flash bad bit - autoincrementing register,
3687 * so must do two writes.
3688 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003689 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003690 /*
3691 * 1030 and 1035 H/W errata, workaround to access
3692 * the ClearFlashBadSignatureBit
3693 */
3694 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3695 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3696 diagRwData |= 0x40000000;
3697 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3698 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3699
3700 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3701 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3702 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3703 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3704
3705 /* wait 1 msec */
3706 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003707 msleep (1);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003708 } else {
3709 mdelay (1);
3710 }
3711 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003713 if (ioc->errata_flag_1064)
3714 pci_disable_io_access(ioc->pcidev);
3715
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303717 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003718 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719 ioc->name, diag0val));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003720 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303721 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722 ioc->name, diag0val));
3723 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3724
3725 /* Write 0xFF to reset the sequencer */
3726 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3727
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003728 if (ioc->bus_type == SAS) {
3729 ioc_state = mpt_GetIocState(ioc, 0);
3730 if ( (GetIocFacts(ioc, sleepFlag,
3731 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303732 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003733 ioc->name, ioc_state));
3734 return -EFAULT;
3735 }
3736 }
3737
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738 for (count=0; count<HZ*20; count++) {
3739 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303740 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3741 "downloadboot successful! (count=%d) IocState=%x\n",
3742 ioc->name, count, ioc_state));
Christoph Hellwig82ffb672005-09-09 16:25:54 +02003743 if (ioc->bus_type == SAS) {
3744 return 0;
3745 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303747 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3748 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749 ioc->name));
3750 return -EFAULT;
3751 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303752 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3753 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754 ioc->name));
3755 return 0;
3756 }
3757 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003758 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759 } else {
3760 mdelay (10);
3761 }
3762 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303763 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3764 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765 return -EFAULT;
3766}
3767
3768/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003769/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770 * KickStart - Perform hard reset of MPT adapter.
3771 * @ioc: Pointer to MPT_ADAPTER structure
3772 * @force: Force hard reset
3773 * @sleepFlag: Specifies whether the process can sleep
3774 *
3775 * This routine places MPT adapter in diagnostic mode via the
3776 * WriteSequence register, and then performs a hard reset of adapter
3777 * via the Diagnostic register.
3778 *
3779 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3780 * or NO_SLEEP (interrupt thread, use mdelay)
3781 * force - 1 if doorbell active, board fault state
3782 * board operational, IOC_RECOVERY or
3783 * IOC_BRINGUP and there is an alt_ioc.
3784 * 0 else
3785 *
3786 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003787 * 1 - hard reset, READY
3788 * 0 - no reset due to History bit, READY
3789 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 * OR reset but failed to come READY
3791 * -2 - no reset, could not enter DIAG mode
3792 * -3 - reset but bad FW bit
3793 */
3794static int
3795KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3796{
3797 int hard_reset_done = 0;
3798 u32 ioc_state=0;
3799 int cnt,cntdn;
3800
Eric Moore29dd3602007-09-14 18:46:51 -06003801 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003802 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 /* Always issue a Msg Unit Reset first. This will clear some
3804 * SCSI bus hang conditions.
3805 */
3806 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3807
3808 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003809 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810 } else {
3811 mdelay (1000);
3812 }
3813 }
3814
3815 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3816 if (hard_reset_done < 0)
3817 return hard_reset_done;
3818
Prakash, Sathya436ace72007-07-24 15:42:08 +05303819 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003820 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821
3822 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3823 for (cnt=0; cnt<cntdn; cnt++) {
3824 ioc_state = mpt_GetIocState(ioc, 1);
3825 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303826 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827 ioc->name, cnt));
3828 return hard_reset_done;
3829 }
3830 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003831 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832 } else {
3833 mdelay (10);
3834 }
3835 }
3836
Eric Moore29dd3602007-09-14 18:46:51 -06003837 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3838 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839 return -1;
3840}
3841
3842/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003843/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844 * mpt_diag_reset - Perform hard reset of the adapter.
3845 * @ioc: Pointer to MPT_ADAPTER structure
3846 * @ignore: Set if to honor and clear to ignore
3847 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003848 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 * else set to NO_SLEEP (use mdelay instead)
3850 *
3851 * This routine places the adapter in diagnostic mode via the
3852 * WriteSequence register and then performs a hard reset of adapter
3853 * via the Diagnostic register. Adapter should be in ready state
3854 * upon successful completion.
3855 *
3856 * Returns: 1 hard reset successful
3857 * 0 no reset performed because reset history bit set
3858 * -2 enabling diagnostic mode failed
3859 * -3 diagnostic reset failed
3860 */
3861static int
3862mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3863{
3864 u32 diag0val;
3865 u32 doorbell;
3866 int hard_reset_done = 0;
3867 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303869 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870
Eric Moorecd2c6192007-01-29 09:47:47 -07003871 /* Clear any existing interrupts */
3872 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3873
Eric Moore87cf8982006-06-27 16:09:26 -06003874 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303875 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003876 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003877 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3878 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3879 if (sleepFlag == CAN_SLEEP)
3880 msleep(1);
3881 else
3882 mdelay(1);
3883
3884 for (count = 0; count < 60; count ++) {
3885 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3886 doorbell &= MPI_IOC_STATE_MASK;
3887
Prakash, Sathya436ace72007-07-24 15:42:08 +05303888 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003889 "looking for READY STATE: doorbell=%x"
3890 " count=%d\n",
3891 ioc->name, doorbell, count));
3892 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003893 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003894 }
3895
3896 /* wait 1 sec */
3897 if (sleepFlag == CAN_SLEEP)
3898 msleep(1000);
3899 else
3900 mdelay(1000);
3901 }
3902 return -1;
3903 }
3904
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 /* Use "Diagnostic reset" method! (only thing available!) */
3906 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3907
Prakash, Sathya436ace72007-07-24 15:42:08 +05303908 if (ioc->debug_level & MPT_DEBUG) {
3909 if (ioc->alt_ioc)
3910 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3911 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303913 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914
3915 /* Do the reset if we are told to ignore the reset history
3916 * or if the reset history is 0
3917 */
3918 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3919 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3920 /* Write magic sequence to WriteSequence register
3921 * Loop until in diagnostic mode
3922 */
3923 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3924 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3925 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3926 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3927 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3928 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3929
3930 /* wait 100 msec */
3931 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003932 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933 } else {
3934 mdelay (100);
3935 }
3936
3937 count++;
3938 if (count > 20) {
3939 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3940 ioc->name, diag0val);
3941 return -2;
3942
3943 }
3944
3945 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3946
Prakash, Sathya436ace72007-07-24 15:42:08 +05303947 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948 ioc->name, diag0val));
3949 }
3950
Prakash, Sathya436ace72007-07-24 15:42:08 +05303951 if (ioc->debug_level & MPT_DEBUG) {
3952 if (ioc->alt_ioc)
3953 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3954 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 /*
3958 * Disable the ARM (Bug fix)
3959 *
3960 */
3961 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003962 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963
3964 /*
3965 * Now hit the reset bit in the Diagnostic register
3966 * (THE BIG HAMMER!) (Clears DRWE bit).
3967 */
3968 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3969 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303970 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 ioc->name));
3972
3973 /*
3974 * Call each currently registered protocol IOC reset handler
3975 * with pre-reset indication.
3976 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3977 * MptResetHandlers[] registered yet.
3978 */
3979 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303980 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981 int r = 0;
3982
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303983 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3984 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303985 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3986 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303987 ioc->name, cb_idx));
3988 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303990 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3991 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303992 ioc->name, ioc->alt_ioc->name, cb_idx));
3993 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 }
3995 }
3996 }
3997 /* FIXME? Examine results here? */
3998 }
3999
Eric Moore0ccdb002006-07-11 17:33:13 -06004000 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304001 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06004002 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304003 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4004 else
4005 cached_fw = NULL;
4006 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 /* If the DownloadBoot operation fails, the
4008 * IOC will be left unusable. This is a fatal error
4009 * case. _diag_reset will return < 0
4010 */
4011 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304012 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4014 break;
4015 }
4016
Prakash, Sathya436ace72007-07-24 15:42:08 +05304017 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304018 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 /* wait 1 sec */
4020 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004021 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 } else {
4023 mdelay (1000);
4024 }
4025 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304026 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004027 printk(MYIOC_s_WARN_FMT
4028 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029 }
4030
4031 } else {
4032 /* Wait for FW to reload and for board
4033 * to go to the READY state.
4034 * Maximum wait is 60 seconds.
4035 * If fail, no error will check again
4036 * with calling program.
4037 */
4038 for (count = 0; count < 60; count ++) {
4039 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4040 doorbell &= MPI_IOC_STATE_MASK;
4041
4042 if (doorbell == MPI_IOC_STATE_READY) {
4043 break;
4044 }
4045
4046 /* wait 1 sec */
4047 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004048 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 } else {
4050 mdelay (1000);
4051 }
4052 }
4053 }
4054 }
4055
4056 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304057 if (ioc->debug_level & MPT_DEBUG) {
4058 if (ioc->alt_ioc)
4059 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4060 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4061 ioc->name, diag0val, diag1val));
4062 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063
4064 /* Clear RESET_HISTORY bit! Place board in the
4065 * diagnostic mode to update the diag register.
4066 */
4067 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4068 count = 0;
4069 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4070 /* Write magic sequence to WriteSequence register
4071 * Loop until in diagnostic mode
4072 */
4073 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4074 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4075 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4076 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4077 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4078 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4079
4080 /* wait 100 msec */
4081 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004082 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083 } else {
4084 mdelay (100);
4085 }
4086
4087 count++;
4088 if (count > 20) {
4089 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4090 ioc->name, diag0val);
4091 break;
4092 }
4093 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4094 }
4095 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4096 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4097 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4098 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4099 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4100 ioc->name);
4101 }
4102
4103 /* Disable Diagnostic Mode
4104 */
4105 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4106
4107 /* Check FW reload status flags.
4108 */
4109 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4110 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4111 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4112 ioc->name, diag0val);
4113 return -3;
4114 }
4115
Prakash, Sathya436ace72007-07-24 15:42:08 +05304116 if (ioc->debug_level & MPT_DEBUG) {
4117 if (ioc->alt_ioc)
4118 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4119 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304121 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122
4123 /*
4124 * Reset flag that says we've enabled event notification
4125 */
4126 ioc->facts.EventState = 0;
4127
4128 if (ioc->alt_ioc)
4129 ioc->alt_ioc->facts.EventState = 0;
4130
4131 return hard_reset_done;
4132}
4133
4134/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004135/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136 * SendIocReset - Send IOCReset request to MPT adapter.
4137 * @ioc: Pointer to MPT_ADAPTER structure
4138 * @reset_type: reset type, expected values are
4139 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004140 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 *
4142 * Send IOCReset request to the MPT adapter.
4143 *
4144 * Returns 0 for success, non-zero for failure.
4145 */
4146static int
4147SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4148{
4149 int r;
4150 u32 state;
4151 int cntdn, count;
4152
Prakash, Sathya436ace72007-07-24 15:42:08 +05304153 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154 ioc->name, reset_type));
4155 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4156 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4157 return r;
4158
4159 /* FW ACK'd request, wait for READY state
4160 */
4161 count = 0;
4162 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4163
4164 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4165 cntdn--;
4166 count++;
4167 if (!cntdn) {
4168 if (sleepFlag != CAN_SLEEP)
4169 count *= 10;
4170
Eric Moore29dd3602007-09-14 18:46:51 -06004171 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
4172 ioc->name, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173 return -ETIME;
4174 }
4175
4176 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004177 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178 } else {
4179 mdelay (1); /* 1 msec delay */
4180 }
4181 }
4182
4183 /* TODO!
4184 * Cleanup all event stuff for this IOC; re-issue EventNotification
4185 * request if needed.
4186 */
4187 if (ioc->facts.Function)
4188 ioc->facts.EventState = 0;
4189
4190 return 0;
4191}
4192
4193/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004194/**
4195 * initChainBuffers - Allocate memory for and initialize chain buffers
4196 * @ioc: Pointer to MPT_ADAPTER structure
4197 *
4198 * Allocates memory for and initializes chain buffers,
4199 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200 */
4201static int
4202initChainBuffers(MPT_ADAPTER *ioc)
4203{
4204 u8 *mem;
4205 int sz, ii, num_chain;
4206 int scale, num_sge, numSGE;
4207
4208 /* ReqToChain size must equal the req_depth
4209 * index = req_idx
4210 */
4211 if (ioc->ReqToChain == NULL) {
4212 sz = ioc->req_depth * sizeof(int);
4213 mem = kmalloc(sz, GFP_ATOMIC);
4214 if (mem == NULL)
4215 return -1;
4216
4217 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304218 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219 ioc->name, mem, sz));
4220 mem = kmalloc(sz, GFP_ATOMIC);
4221 if (mem == NULL)
4222 return -1;
4223
4224 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304225 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 ioc->name, mem, sz));
4227 }
4228 for (ii = 0; ii < ioc->req_depth; ii++) {
4229 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4230 }
4231
4232 /* ChainToChain size must equal the total number
4233 * of chain buffers to be allocated.
4234 * index = chain_idx
4235 *
4236 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004237 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 *
4239 * num_sge = num sge in request frame + last chain buffer
4240 * scale = num sge per chain buffer if no chain element
4241 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304242 scale = ioc->req_sz / ioc->SGE_size;
4243 if (ioc->sg_addr_size == sizeof(u64))
4244 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304246 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304248 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304250 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304252 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4253 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304255 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256 ioc->name, num_sge, numSGE));
4257
4258 if ( numSGE > MPT_SCSI_SG_DEPTH )
4259 numSGE = MPT_SCSI_SG_DEPTH;
4260
4261 num_chain = 1;
4262 while (numSGE - num_sge > 0) {
4263 num_chain++;
4264 num_sge += (scale - 1);
4265 }
4266 num_chain++;
4267
Prakash, Sathya436ace72007-07-24 15:42:08 +05304268 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269 ioc->name, numSGE, num_sge, num_chain));
4270
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004271 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272 num_chain *= MPT_SCSI_CAN_QUEUE;
4273 else
4274 num_chain *= MPT_FC_CAN_QUEUE;
4275
4276 ioc->num_chain = num_chain;
4277
4278 sz = num_chain * sizeof(int);
4279 if (ioc->ChainToChain == NULL) {
4280 mem = kmalloc(sz, GFP_ATOMIC);
4281 if (mem == NULL)
4282 return -1;
4283
4284 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304285 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286 ioc->name, mem, sz));
4287 } else {
4288 mem = (u8 *) ioc->ChainToChain;
4289 }
4290 memset(mem, 0xFF, sz);
4291 return num_chain;
4292}
4293
4294/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004295/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4297 * @ioc: Pointer to MPT_ADAPTER structure
4298 *
4299 * This routine allocates memory for the MPT reply and request frame
4300 * pools (if necessary), and primes the IOC reply FIFO with
4301 * reply frames.
4302 *
4303 * Returns 0 for success, non-zero for failure.
4304 */
4305static int
4306PrimeIocFifos(MPT_ADAPTER *ioc)
4307{
4308 MPT_FRAME_HDR *mf;
4309 unsigned long flags;
4310 dma_addr_t alloc_dma;
4311 u8 *mem;
4312 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304313 u64 dma_mask;
4314
4315 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316
4317 /* Prime reply FIFO... */
4318
4319 if (ioc->reply_frames == NULL) {
4320 if ( (num_chain = initChainBuffers(ioc)) < 0)
4321 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304322 /*
4323 * 1078 errata workaround for the 36GB limitation
4324 */
4325 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
4326 ioc->dma_mask > DMA_35BIT_MASK) {
4327 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4328 && !pci_set_consistent_dma_mask(ioc->pcidev,
4329 DMA_BIT_MASK(32))) {
4330 dma_mask = DMA_35BIT_MASK;
4331 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4332 "setting 35 bit addressing for "
4333 "Request/Reply/Chain and Sense Buffers\n",
4334 ioc->name));
4335 } else {
4336 /*Reseting DMA mask to 64 bit*/
4337 pci_set_dma_mask(ioc->pcidev,
4338 DMA_BIT_MASK(64));
4339 pci_set_consistent_dma_mask(ioc->pcidev,
4340 DMA_BIT_MASK(64));
4341
4342 printk(MYIOC_s_ERR_FMT
4343 "failed setting 35 bit addressing for "
4344 "Request/Reply/Chain and Sense Buffers\n",
4345 ioc->name);
4346 return -1;
4347 }
4348 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349
4350 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304351 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304353 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 ioc->name, reply_sz, reply_sz));
4355
4356 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304357 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304359 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360 ioc->name, sz, sz));
4361 total_size += sz;
4362
4363 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304364 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304366 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 ioc->name, sz, sz, num_chain));
4368
4369 total_size += sz;
4370 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4371 if (mem == NULL) {
4372 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4373 ioc->name);
4374 goto out_fail;
4375 }
4376
Prakash, Sathya436ace72007-07-24 15:42:08 +05304377 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4379
4380 memset(mem, 0, total_size);
4381 ioc->alloc_total += total_size;
4382 ioc->alloc = mem;
4383 ioc->alloc_dma = alloc_dma;
4384 ioc->alloc_sz = total_size;
4385 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4386 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4387
Prakash, Sathya436ace72007-07-24 15:42:08 +05304388 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004389 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4390
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391 alloc_dma += reply_sz;
4392 mem += reply_sz;
4393
4394 /* Request FIFO - WE manage this! */
4395
4396 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4397 ioc->req_frames_dma = alloc_dma;
4398
Prakash, Sathya436ace72007-07-24 15:42:08 +05304399 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400 ioc->name, mem, (void *)(ulong)alloc_dma));
4401
4402 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4403
4404#if defined(CONFIG_MTRR) && 0
4405 /*
4406 * Enable Write Combining MTRR for IOC's memory region.
4407 * (at least as much as we can; "size and base must be
4408 * multiples of 4 kiB"
4409 */
4410 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4411 sz,
4412 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304413 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 ioc->name, ioc->req_frames_dma, sz));
4415#endif
4416
4417 for (i = 0; i < ioc->req_depth; i++) {
4418 alloc_dma += ioc->req_sz;
4419 mem += ioc->req_sz;
4420 }
4421
4422 ioc->ChainBuffer = mem;
4423 ioc->ChainBufferDMA = alloc_dma;
4424
Prakash, Sathya436ace72007-07-24 15:42:08 +05304425 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4427
4428 /* Initialize the free chain Q.
4429 */
4430
4431 INIT_LIST_HEAD(&ioc->FreeChainQ);
4432
4433 /* Post the chain buffers to the FreeChainQ.
4434 */
4435 mem = (u8 *)ioc->ChainBuffer;
4436 for (i=0; i < num_chain; i++) {
4437 mf = (MPT_FRAME_HDR *) mem;
4438 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4439 mem += ioc->req_sz;
4440 }
4441
4442 /* Initialize Request frames linked list
4443 */
4444 alloc_dma = ioc->req_frames_dma;
4445 mem = (u8 *) ioc->req_frames;
4446
4447 spin_lock_irqsave(&ioc->FreeQlock, flags);
4448 INIT_LIST_HEAD(&ioc->FreeQ);
4449 for (i = 0; i < ioc->req_depth; i++) {
4450 mf = (MPT_FRAME_HDR *) mem;
4451
4452 /* Queue REQUESTs *internally*! */
4453 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4454
4455 mem += ioc->req_sz;
4456 }
4457 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4458
4459 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4460 ioc->sense_buf_pool =
4461 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4462 if (ioc->sense_buf_pool == NULL) {
4463 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4464 ioc->name);
4465 goto out_fail;
4466 }
4467
4468 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4469 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304470 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4472
4473 }
4474
4475 /* Post Reply frames to FIFO
4476 */
4477 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304478 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4480
4481 for (i = 0; i < ioc->reply_depth; i++) {
4482 /* Write each address to the IOC! */
4483 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4484 alloc_dma += ioc->reply_sz;
4485 }
4486
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304487 if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
4488 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4489 ioc->dma_mask))
4490 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4491 "restoring 64 bit addressing\n", ioc->name));
4492
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493 return 0;
4494
4495out_fail:
4496 if (ioc->alloc != NULL) {
4497 sz = ioc->alloc_sz;
4498 pci_free_consistent(ioc->pcidev,
4499 sz,
4500 ioc->alloc, ioc->alloc_dma);
4501 ioc->reply_frames = NULL;
4502 ioc->req_frames = NULL;
4503 ioc->alloc_total -= sz;
4504 }
4505 if (ioc->sense_buf_pool != NULL) {
4506 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4507 pci_free_consistent(ioc->pcidev,
4508 sz,
4509 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4510 ioc->sense_buf_pool = NULL;
4511 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304512
4513 if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
4514 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4515 DMA_BIT_MASK(64)))
4516 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4517 "restoring 64 bit addressing\n", ioc->name));
4518
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519 return -1;
4520}
4521
4522/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4523/**
4524 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4525 * from IOC via doorbell handshake method.
4526 * @ioc: Pointer to MPT_ADAPTER structure
4527 * @reqBytes: Size of the request in bytes
4528 * @req: Pointer to MPT request frame
4529 * @replyBytes: Expected size of the reply in bytes
4530 * @u16reply: Pointer to area where reply should be written
4531 * @maxwait: Max wait time for a reply (in seconds)
4532 * @sleepFlag: Specifies whether the process can sleep
4533 *
4534 * NOTES: It is the callers responsibility to byte-swap fields in the
4535 * request which are greater than 1 byte in size. It is also the
4536 * callers responsibility to byte-swap response fields which are
4537 * greater than 1 byte in size.
4538 *
4539 * Returns 0 for success, non-zero for failure.
4540 */
4541static int
4542mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004543 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544{
4545 MPIDefaultReply_t *mptReply;
4546 int failcnt = 0;
4547 int t;
4548
4549 /*
4550 * Get ready to cache a handshake reply
4551 */
4552 ioc->hs_reply_idx = 0;
4553 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4554 mptReply->MsgLength = 0;
4555
4556 /*
4557 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4558 * then tell IOC that we want to handshake a request of N words.
4559 * (WRITE u32val to Doorbell reg).
4560 */
4561 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4562 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4563 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4564 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4565
4566 /*
4567 * Wait for IOC's doorbell handshake int
4568 */
4569 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4570 failcnt++;
4571
Prakash, Sathya436ace72007-07-24 15:42:08 +05304572 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4574
4575 /* Read doorbell and check for active bit */
4576 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4577 return -1;
4578
4579 /*
4580 * Clear doorbell int (WRITE 0 to IntStatus reg),
4581 * then wait for IOC to ACKnowledge that it's ready for
4582 * our handshake request.
4583 */
4584 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4585 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4586 failcnt++;
4587
4588 if (!failcnt) {
4589 int ii;
4590 u8 *req_as_bytes = (u8 *) req;
4591
4592 /*
4593 * Stuff request words via doorbell handshake,
4594 * with ACK from IOC for each.
4595 */
4596 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4597 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4598 (req_as_bytes[(ii*4) + 1] << 8) |
4599 (req_as_bytes[(ii*4) + 2] << 16) |
4600 (req_as_bytes[(ii*4) + 3] << 24));
4601
4602 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4603 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4604 failcnt++;
4605 }
4606
Prakash, Sathya436ace72007-07-24 15:42:08 +05304607 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004608 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609
Prakash, Sathya436ace72007-07-24 15:42:08 +05304610 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4612
4613 /*
4614 * Wait for completion of doorbell handshake reply from the IOC
4615 */
4616 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4617 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004618
Prakash, Sathya436ace72007-07-24 15:42:08 +05304619 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4621
4622 /*
4623 * Copy out the cached reply...
4624 */
4625 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4626 u16reply[ii] = ioc->hs_reply[ii];
4627 } else {
4628 return -99;
4629 }
4630
4631 return -failcnt;
4632}
4633
4634/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004635/**
4636 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637 * @ioc: Pointer to MPT_ADAPTER structure
4638 * @howlong: How long to wait (in seconds)
4639 * @sleepFlag: Specifies whether the process can sleep
4640 *
4641 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004642 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4643 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 *
4645 * Returns a negative value on failure, else wait loop count.
4646 */
4647static int
4648WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4649{
4650 int cntdn;
4651 int count = 0;
4652 u32 intstat=0;
4653
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004654 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655
4656 if (sleepFlag == CAN_SLEEP) {
4657 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004658 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004659 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4660 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4661 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662 count++;
4663 }
4664 } else {
4665 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004666 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4668 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4669 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670 count++;
4671 }
4672 }
4673
4674 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304675 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004676 ioc->name, count));
4677 return count;
4678 }
4679
4680 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4681 ioc->name, count, intstat);
4682 return -1;
4683}
4684
4685/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004686/**
4687 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688 * @ioc: Pointer to MPT_ADAPTER structure
4689 * @howlong: How long to wait (in seconds)
4690 * @sleepFlag: Specifies whether the process can sleep
4691 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004692 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4693 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694 *
4695 * Returns a negative value on failure, else wait loop count.
4696 */
4697static int
4698WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4699{
4700 int cntdn;
4701 int count = 0;
4702 u32 intstat=0;
4703
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004704 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705 if (sleepFlag == CAN_SLEEP) {
4706 while (--cntdn) {
4707 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4708 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4709 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004710 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711 count++;
4712 }
4713 } else {
4714 while (--cntdn) {
4715 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4716 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4717 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004718 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 count++;
4720 }
4721 }
4722
4723 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304724 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725 ioc->name, count, howlong));
4726 return count;
4727 }
4728
4729 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4730 ioc->name, count, intstat);
4731 return -1;
4732}
4733
4734/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004735/**
4736 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737 * @ioc: Pointer to MPT_ADAPTER structure
4738 * @howlong: How long to wait (in seconds)
4739 * @sleepFlag: Specifies whether the process can sleep
4740 *
4741 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4742 * Reply is cached to IOC private area large enough to hold a maximum
4743 * of 128 bytes of reply data.
4744 *
4745 * Returns a negative value on failure, else size of reply in WORDS.
4746 */
4747static int
4748WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4749{
4750 int u16cnt = 0;
4751 int failcnt = 0;
4752 int t;
4753 u16 *hs_reply = ioc->hs_reply;
4754 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4755 u16 hword;
4756
4757 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4758
4759 /*
4760 * Get first two u16's so we can look at IOC's intended reply MsgLength
4761 */
4762 u16cnt=0;
4763 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4764 failcnt++;
4765 } else {
4766 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4767 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4768 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4769 failcnt++;
4770 else {
4771 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4772 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4773 }
4774 }
4775
Prakash, Sathya436ace72007-07-24 15:42:08 +05304776 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004777 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4779
4780 /*
4781 * If no error (and IOC said MsgLength is > 0), piece together
4782 * reply 16 bits at a time.
4783 */
4784 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4785 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4786 failcnt++;
4787 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4788 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004789 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 hs_reply[u16cnt] = hword;
4791 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4792 }
4793
4794 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4795 failcnt++;
4796 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4797
4798 if (failcnt) {
4799 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4800 ioc->name);
4801 return -failcnt;
4802 }
4803#if 0
4804 else if (u16cnt != (2 * mptReply->MsgLength)) {
4805 return -101;
4806 }
4807 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4808 return -102;
4809 }
4810#endif
4811
Prakash, Sathya436ace72007-07-24 15:42:08 +05304812 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004813 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814
Prakash, Sathya436ace72007-07-24 15:42:08 +05304815 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816 ioc->name, t, u16cnt/2));
4817 return u16cnt/2;
4818}
4819
4820/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004821/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822 * GetLanConfigPages - Fetch LANConfig pages.
4823 * @ioc: Pointer to MPT_ADAPTER structure
4824 *
4825 * Return: 0 for success
4826 * -ENOMEM if no memory available
4827 * -EPERM if not allowed due to ISR context
4828 * -EAGAIN if no msg frames currently available
4829 * -EFAULT for non-successful reply or no reply (timeout)
4830 */
4831static int
4832GetLanConfigPages(MPT_ADAPTER *ioc)
4833{
4834 ConfigPageHeader_t hdr;
4835 CONFIGPARMS cfg;
4836 LANPage0_t *ppage0_alloc;
4837 dma_addr_t page0_dma;
4838 LANPage1_t *ppage1_alloc;
4839 dma_addr_t page1_dma;
4840 int rc = 0;
4841 int data_sz;
4842 int copy_sz;
4843
4844 /* Get LAN Page 0 header */
4845 hdr.PageVersion = 0;
4846 hdr.PageLength = 0;
4847 hdr.PageNumber = 0;
4848 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004849 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 cfg.physAddr = -1;
4851 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4852 cfg.dir = 0;
4853 cfg.pageAddr = 0;
4854 cfg.timeout = 0;
4855
4856 if ((rc = mpt_config(ioc, &cfg)) != 0)
4857 return rc;
4858
4859 if (hdr.PageLength > 0) {
4860 data_sz = hdr.PageLength * 4;
4861 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4862 rc = -ENOMEM;
4863 if (ppage0_alloc) {
4864 memset((u8 *)ppage0_alloc, 0, data_sz);
4865 cfg.physAddr = page0_dma;
4866 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4867
4868 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4869 /* save the data */
4870 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4871 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4872
4873 }
4874
4875 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4876
4877 /* FIXME!
4878 * Normalize endianness of structure data,
4879 * by byte-swapping all > 1 byte fields!
4880 */
4881
4882 }
4883
4884 if (rc)
4885 return rc;
4886 }
4887
4888 /* Get LAN Page 1 header */
4889 hdr.PageVersion = 0;
4890 hdr.PageLength = 0;
4891 hdr.PageNumber = 1;
4892 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004893 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894 cfg.physAddr = -1;
4895 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4896 cfg.dir = 0;
4897 cfg.pageAddr = 0;
4898
4899 if ((rc = mpt_config(ioc, &cfg)) != 0)
4900 return rc;
4901
4902 if (hdr.PageLength == 0)
4903 return 0;
4904
4905 data_sz = hdr.PageLength * 4;
4906 rc = -ENOMEM;
4907 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4908 if (ppage1_alloc) {
4909 memset((u8 *)ppage1_alloc, 0, data_sz);
4910 cfg.physAddr = page1_dma;
4911 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4912
4913 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4914 /* save the data */
4915 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4916 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4917 }
4918
4919 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4920
4921 /* FIXME!
4922 * Normalize endianness of structure data,
4923 * by byte-swapping all > 1 byte fields!
4924 */
4925
4926 }
4927
4928 return rc;
4929}
4930
4931/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004932/**
4933 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004934 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004935 * @persist_opcode: see below
4936 *
4937 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4938 * devices not currently present.
4939 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4940 *
4941 * NOTE: Don't use not this function during interrupt time.
4942 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004943 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004944 */
4945
4946/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4947int
4948mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4949{
4950 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4951 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4952 MPT_FRAME_HDR *mf = NULL;
4953 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304954 int ret = 0;
4955 unsigned long timeleft;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004956
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304957 mutex_lock(&ioc->mptbase_cmds.mutex);
4958
4959 /* init the internal cmd struct */
4960 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
4961 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004962
4963 /* insure garbage is not sent to fw */
4964 switch(persist_opcode) {
4965
4966 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4967 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4968 break;
4969
4970 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304971 ret = -1;
4972 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004973 }
4974
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304975 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
4976 __func__, persist_opcode);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004977
4978 /* Get a MF for this command.
4979 */
4980 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304981 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
4982 ret = -1;
4983 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004984 }
4985
4986 mpi_hdr = (MPIHeader_t *) mf;
4987 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4988 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4989 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4990 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4991 sasIoUnitCntrReq->Operation = persist_opcode;
4992
Christoph Hellwig82ffb672005-09-09 16:25:54 +02004993 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304994 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
4995 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
4996 ret = -ETIME;
4997 printk(KERN_DEBUG "%s: failed\n", __func__);
4998 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
4999 goto out;
5000 if (!timeleft) {
5001 printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n",
5002 ioc->name, __func__);
5003 mpt_HardResetHandler(ioc, CAN_SLEEP);
5004 mpt_free_msg_frame(ioc, mf);
5005 }
5006 goto out;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005007 }
5008
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305009 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
5010 ret = -1;
5011 goto out;
5012 }
5013
5014 sasIoUnitCntrReply =
5015 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5016 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5017 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5018 __func__, sasIoUnitCntrReply->IOCStatus,
5019 sasIoUnitCntrReply->IOCLogInfo);
5020 printk(KERN_DEBUG "%s: failed\n", __func__);
5021 ret = -1;
5022 } else
5023 printk(KERN_DEBUG "%s: success\n", __func__);
5024 out:
5025
5026 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5027 mutex_unlock(&ioc->mptbase_cmds.mutex);
5028 return ret;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02005029}
5030
5031/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005032
5033static void
5034mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5035 MpiEventDataRaid_t * pRaidEventData)
5036{
5037 int volume;
5038 int reason;
5039 int disk;
5040 int status;
5041 int flags;
5042 int state;
5043
5044 volume = pRaidEventData->VolumeID;
5045 reason = pRaidEventData->ReasonCode;
5046 disk = pRaidEventData->PhysDiskNum;
5047 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5048 flags = (status >> 0) & 0xff;
5049 state = (status >> 8) & 0xff;
5050
5051 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5052 return;
5053 }
5054
5055 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5056 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5057 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005058 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5059 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005060 } else {
5061 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5062 ioc->name, volume);
5063 }
5064
5065 switch(reason) {
5066 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5067 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5068 ioc->name);
5069 break;
5070
5071 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5072
5073 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5074 ioc->name);
5075 break;
5076
5077 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5078 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5079 ioc->name);
5080 break;
5081
5082 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5083 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5084 ioc->name,
5085 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5086 ? "optimal"
5087 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5088 ? "degraded"
5089 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5090 ? "failed"
5091 : "state unknown",
5092 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5093 ? ", enabled" : "",
5094 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5095 ? ", quiesced" : "",
5096 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5097 ? ", resync in progress" : "" );
5098 break;
5099
5100 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5101 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5102 ioc->name, disk);
5103 break;
5104
5105 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5106 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5107 ioc->name);
5108 break;
5109
5110 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5111 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5112 ioc->name);
5113 break;
5114
5115 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5116 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5117 ioc->name);
5118 break;
5119
5120 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5121 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5122 ioc->name,
5123 state == MPI_PHYSDISK0_STATUS_ONLINE
5124 ? "online"
5125 : state == MPI_PHYSDISK0_STATUS_MISSING
5126 ? "missing"
5127 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5128 ? "not compatible"
5129 : state == MPI_PHYSDISK0_STATUS_FAILED
5130 ? "failed"
5131 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5132 ? "initializing"
5133 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5134 ? "offline requested"
5135 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5136 ? "failed requested"
5137 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5138 ? "offline"
5139 : "state unknown",
5140 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5141 ? ", out of sync" : "",
5142 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5143 ? ", quiesced" : "" );
5144 break;
5145
5146 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5147 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5148 ioc->name, disk);
5149 break;
5150
5151 case MPI_EVENT_RAID_RC_SMART_DATA:
5152 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5153 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5154 break;
5155
5156 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5157 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5158 ioc->name, disk);
5159 break;
5160 }
5161}
5162
5163/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005164/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5166 * @ioc: Pointer to MPT_ADAPTER structure
5167 *
5168 * Returns: 0 for success
5169 * -ENOMEM if no memory available
5170 * -EPERM if not allowed due to ISR context
5171 * -EAGAIN if no msg frames currently available
5172 * -EFAULT for non-successful reply or no reply (timeout)
5173 */
5174static int
5175GetIoUnitPage2(MPT_ADAPTER *ioc)
5176{
5177 ConfigPageHeader_t hdr;
5178 CONFIGPARMS cfg;
5179 IOUnitPage2_t *ppage_alloc;
5180 dma_addr_t page_dma;
5181 int data_sz;
5182 int rc;
5183
5184 /* Get the page header */
5185 hdr.PageVersion = 0;
5186 hdr.PageLength = 0;
5187 hdr.PageNumber = 2;
5188 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005189 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190 cfg.physAddr = -1;
5191 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5192 cfg.dir = 0;
5193 cfg.pageAddr = 0;
5194 cfg.timeout = 0;
5195
5196 if ((rc = mpt_config(ioc, &cfg)) != 0)
5197 return rc;
5198
5199 if (hdr.PageLength == 0)
5200 return 0;
5201
5202 /* Read the config page */
5203 data_sz = hdr.PageLength * 4;
5204 rc = -ENOMEM;
5205 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5206 if (ppage_alloc) {
5207 memset((u8 *)ppage_alloc, 0, data_sz);
5208 cfg.physAddr = page_dma;
5209 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5210
5211 /* If Good, save data */
5212 if ((rc = mpt_config(ioc, &cfg)) == 0)
5213 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5214
5215 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5216 }
5217
5218 return rc;
5219}
5220
5221/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005222/**
5223 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 * @ioc: Pointer to a Adapter Strucutre
5225 * @portnum: IOC port number
5226 *
5227 * Return: -EFAULT if read of config page header fails
5228 * or if no nvram
5229 * If read of SCSI Port Page 0 fails,
5230 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5231 * Adapter settings: async, narrow
5232 * Return 1
5233 * If read of SCSI Port Page 2 fails,
5234 * Adapter settings valid
5235 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5236 * Return 1
5237 * Else
5238 * Both valid
5239 * Return 0
5240 * CHECK - what type of locking mechanisms should be used????
5241 */
5242static int
5243mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5244{
5245 u8 *pbuf;
5246 dma_addr_t buf_dma;
5247 CONFIGPARMS cfg;
5248 ConfigPageHeader_t header;
5249 int ii;
5250 int data, rc = 0;
5251
5252 /* Allocate memory
5253 */
5254 if (!ioc->spi_data.nvram) {
5255 int sz;
5256 u8 *mem;
5257 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5258 mem = kmalloc(sz, GFP_ATOMIC);
5259 if (mem == NULL)
5260 return -EFAULT;
5261
5262 ioc->spi_data.nvram = (int *) mem;
5263
Prakash, Sathya436ace72007-07-24 15:42:08 +05305264 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265 ioc->name, ioc->spi_data.nvram, sz));
5266 }
5267
5268 /* Invalidate NVRAM information
5269 */
5270 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5271 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5272 }
5273
5274 /* Read SPP0 header, allocate memory, then read page.
5275 */
5276 header.PageVersion = 0;
5277 header.PageLength = 0;
5278 header.PageNumber = 0;
5279 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005280 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005281 cfg.physAddr = -1;
5282 cfg.pageAddr = portnum;
5283 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5284 cfg.dir = 0;
5285 cfg.timeout = 0; /* use default */
5286 if (mpt_config(ioc, &cfg) != 0)
5287 return -EFAULT;
5288
5289 if (header.PageLength > 0) {
5290 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5291 if (pbuf) {
5292 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5293 cfg.physAddr = buf_dma;
5294 if (mpt_config(ioc, &cfg) != 0) {
5295 ioc->spi_data.maxBusWidth = MPT_NARROW;
5296 ioc->spi_data.maxSyncOffset = 0;
5297 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5298 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5299 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305300 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5301 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005302 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005303 } else {
5304 /* Save the Port Page 0 data
5305 */
5306 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5307 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5308 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5309
5310 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5311 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005312 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5313 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314 ioc->name, pPP0->Capabilities));
5315 }
5316 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5317 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5318 if (data) {
5319 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5320 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5321 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305322 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5323 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005324 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005325 } else {
5326 ioc->spi_data.maxSyncOffset = 0;
5327 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5328 }
5329
5330 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5331
5332 /* Update the minSyncFactor based on bus type.
5333 */
5334 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5335 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5336
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005337 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305339 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5340 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005341 ioc->name, ioc->spi_data.minSyncFactor));
5342 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343 }
5344 }
5345 if (pbuf) {
5346 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5347 }
5348 }
5349 }
5350
5351 /* SCSI Port Page 2 - Read the header then the page.
5352 */
5353 header.PageVersion = 0;
5354 header.PageLength = 0;
5355 header.PageNumber = 2;
5356 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005357 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358 cfg.physAddr = -1;
5359 cfg.pageAddr = portnum;
5360 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5361 cfg.dir = 0;
5362 if (mpt_config(ioc, &cfg) != 0)
5363 return -EFAULT;
5364
5365 if (header.PageLength > 0) {
5366 /* Allocate memory and read SCSI Port Page 2
5367 */
5368 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5369 if (pbuf) {
5370 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5371 cfg.physAddr = buf_dma;
5372 if (mpt_config(ioc, &cfg) != 0) {
5373 /* Nvram data is left with INVALID mark
5374 */
5375 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005376 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5377
5378 /* This is an ATTO adapter, read Page2 accordingly
5379 */
5380 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5381 ATTODeviceInfo_t *pdevice = NULL;
5382 u16 ATTOFlags;
5383
5384 /* Save the Port Page 2 data
5385 * (reformat into a 32bit quantity)
5386 */
5387 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5388 pdevice = &pPP2->DeviceSettings[ii];
5389 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5390 data = 0;
5391
5392 /* Translate ATTO device flags to LSI format
5393 */
5394 if (ATTOFlags & ATTOFLAG_DISC)
5395 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5396 if (ATTOFlags & ATTOFLAG_ID_ENB)
5397 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5398 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5399 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5400 if (ATTOFlags & ATTOFLAG_TAGGED)
5401 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5402 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5403 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5404
5405 data = (data << 16) | (pdevice->Period << 8) | 10;
5406 ioc->spi_data.nvram[ii] = data;
5407 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005408 } else {
5409 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5410 MpiDeviceInfo_t *pdevice = NULL;
5411
Moore, Ericd8e925d2006-01-16 18:53:06 -07005412 /*
5413 * Save "Set to Avoid SCSI Bus Resets" flag
5414 */
5415 ioc->spi_data.bus_reset =
5416 (le32_to_cpu(pPP2->PortFlags) &
5417 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5418 0 : 1 ;
5419
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420 /* Save the Port Page 2 data
5421 * (reformat into a 32bit quantity)
5422 */
5423 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5424 ioc->spi_data.PortFlags = data;
5425 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5426 pdevice = &pPP2->DeviceSettings[ii];
5427 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5428 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5429 ioc->spi_data.nvram[ii] = data;
5430 }
5431 }
5432
5433 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5434 }
5435 }
5436
5437 /* Update Adapter limits with those from NVRAM
5438 * Comment: Don't need to do this. Target performance
5439 * parameters will never exceed the adapters limits.
5440 */
5441
5442 return rc;
5443}
5444
5445/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005446/**
5447 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 * @ioc: Pointer to a Adapter Strucutre
5449 * @portnum: IOC port number
5450 *
5451 * Return: -EFAULT if read of config page header fails
5452 * or 0 if success.
5453 */
5454static int
5455mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5456{
5457 CONFIGPARMS cfg;
5458 ConfigPageHeader_t header;
5459
5460 /* Read the SCSI Device Page 1 header
5461 */
5462 header.PageVersion = 0;
5463 header.PageLength = 0;
5464 header.PageNumber = 1;
5465 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005466 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467 cfg.physAddr = -1;
5468 cfg.pageAddr = portnum;
5469 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5470 cfg.dir = 0;
5471 cfg.timeout = 0;
5472 if (mpt_config(ioc, &cfg) != 0)
5473 return -EFAULT;
5474
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005475 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5476 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477
5478 header.PageVersion = 0;
5479 header.PageLength = 0;
5480 header.PageNumber = 0;
5481 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5482 if (mpt_config(ioc, &cfg) != 0)
5483 return -EFAULT;
5484
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005485 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5486 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487
Prakash, Sathya436ace72007-07-24 15:42:08 +05305488 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5490
Prakash, Sathya436ace72007-07-24 15:42:08 +05305491 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5493 return 0;
5494}
5495
Eric Mooreb506ade2007-01-29 09:45:37 -07005496/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005497 * mpt_inactive_raid_list_free - This clears this link list.
5498 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005499 **/
5500static void
5501mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5502{
5503 struct inactive_raid_component_info *component_info, *pNext;
5504
5505 if (list_empty(&ioc->raid_data.inactive_list))
5506 return;
5507
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005508 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005509 list_for_each_entry_safe(component_info, pNext,
5510 &ioc->raid_data.inactive_list, list) {
5511 list_del(&component_info->list);
5512 kfree(component_info);
5513 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005514 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005515}
5516
5517/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005518 * 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 -07005519 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005520 * @ioc : pointer to per adapter structure
5521 * @channel : volume channel
5522 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005523 **/
5524static void
5525mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5526{
5527 CONFIGPARMS cfg;
5528 ConfigPageHeader_t hdr;
5529 dma_addr_t dma_handle;
5530 pRaidVolumePage0_t buffer = NULL;
5531 int i;
5532 RaidPhysDiskPage0_t phys_disk;
5533 struct inactive_raid_component_info *component_info;
5534 int handle_inactive_volumes;
5535
5536 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5537 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5538 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5539 cfg.pageAddr = (channel << 8) + id;
5540 cfg.cfghdr.hdr = &hdr;
5541 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5542
5543 if (mpt_config(ioc, &cfg) != 0)
5544 goto out;
5545
5546 if (!hdr.PageLength)
5547 goto out;
5548
5549 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5550 &dma_handle);
5551
5552 if (!buffer)
5553 goto out;
5554
5555 cfg.physAddr = dma_handle;
5556 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5557
5558 if (mpt_config(ioc, &cfg) != 0)
5559 goto out;
5560
5561 if (!buffer->NumPhysDisks)
5562 goto out;
5563
5564 handle_inactive_volumes =
5565 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5566 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5567 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5568 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5569
5570 if (!handle_inactive_volumes)
5571 goto out;
5572
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005573 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005574 for (i = 0; i < buffer->NumPhysDisks; i++) {
5575 if(mpt_raid_phys_disk_pg0(ioc,
5576 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5577 continue;
5578
5579 if ((component_info = kmalloc(sizeof (*component_info),
5580 GFP_KERNEL)) == NULL)
5581 continue;
5582
5583 component_info->volumeID = id;
5584 component_info->volumeBus = channel;
5585 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5586 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5587 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5588 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5589
5590 list_add_tail(&component_info->list,
5591 &ioc->raid_data.inactive_list);
5592 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005593 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005594
5595 out:
5596 if (buffer)
5597 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5598 dma_handle);
5599}
5600
5601/**
5602 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5603 * @ioc: Pointer to a Adapter Structure
5604 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5605 * @phys_disk: requested payload data returned
5606 *
5607 * Return:
5608 * 0 on success
5609 * -EFAULT if read of config page header fails or data pointer not NULL
5610 * -ENOMEM if pci_alloc failed
5611 **/
5612int
5613mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5614{
5615 CONFIGPARMS cfg;
5616 ConfigPageHeader_t hdr;
5617 dma_addr_t dma_handle;
5618 pRaidPhysDiskPage0_t buffer = NULL;
5619 int rc;
5620
5621 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5622 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5623
5624 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5625 cfg.cfghdr.hdr = &hdr;
5626 cfg.physAddr = -1;
5627 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5628
5629 if (mpt_config(ioc, &cfg) != 0) {
5630 rc = -EFAULT;
5631 goto out;
5632 }
5633
5634 if (!hdr.PageLength) {
5635 rc = -EFAULT;
5636 goto out;
5637 }
5638
5639 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5640 &dma_handle);
5641
5642 if (!buffer) {
5643 rc = -ENOMEM;
5644 goto out;
5645 }
5646
5647 cfg.physAddr = dma_handle;
5648 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5649 cfg.pageAddr = phys_disk_num;
5650
5651 if (mpt_config(ioc, &cfg) != 0) {
5652 rc = -EFAULT;
5653 goto out;
5654 }
5655
5656 rc = 0;
5657 memcpy(phys_disk, buffer, sizeof(*buffer));
5658 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5659
5660 out:
5661
5662 if (buffer)
5663 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5664 dma_handle);
5665
5666 return rc;
5667}
5668
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669/**
5670 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5671 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005672 *
5673 * Return:
5674 * 0 on success
5675 * -EFAULT if read of config page header fails or data pointer not NULL
5676 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005677 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005678int
5679mpt_findImVolumes(MPT_ADAPTER *ioc)
5680{
5681 IOCPage2_t *pIoc2;
5682 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683 dma_addr_t ioc2_dma;
5684 CONFIGPARMS cfg;
5685 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005686 int rc = 0;
5687 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005688 int i;
5689
5690 if (!ioc->ir_firmware)
5691 return 0;
5692
5693 /* Free the old page
5694 */
5695 kfree(ioc->raid_data.pIocPg2);
5696 ioc->raid_data.pIocPg2 = NULL;
5697 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698
5699 /* Read IOCP2 header then the page.
5700 */
5701 header.PageVersion = 0;
5702 header.PageLength = 0;
5703 header.PageNumber = 2;
5704 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005705 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706 cfg.physAddr = -1;
5707 cfg.pageAddr = 0;
5708 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5709 cfg.dir = 0;
5710 cfg.timeout = 0;
5711 if (mpt_config(ioc, &cfg) != 0)
5712 return -EFAULT;
5713
5714 if (header.PageLength == 0)
5715 return -EFAULT;
5716
5717 iocpage2sz = header.PageLength * 4;
5718 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5719 if (!pIoc2)
5720 return -ENOMEM;
5721
5722 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5723 cfg.physAddr = ioc2_dma;
5724 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005725 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005726
Eric Mooreb506ade2007-01-29 09:45:37 -07005727 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5728 if (!mem)
5729 goto out;
5730
Linus Torvalds1da177e2005-04-16 15:20:36 -07005731 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005732 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005733
Eric Mooreb506ade2007-01-29 09:45:37 -07005734 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735
Eric Mooreb506ade2007-01-29 09:45:37 -07005736 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5737 mpt_inactive_raid_volumes(ioc,
5738 pIoc2->RaidVolume[i].VolumeBus,
5739 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740
Eric Mooreb506ade2007-01-29 09:45:37 -07005741 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5743
5744 return rc;
5745}
5746
Moore, Ericc972c702006-03-14 09:14:06 -07005747static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5749{
5750 IOCPage3_t *pIoc3;
5751 u8 *mem;
5752 CONFIGPARMS cfg;
5753 ConfigPageHeader_t header;
5754 dma_addr_t ioc3_dma;
5755 int iocpage3sz = 0;
5756
5757 /* Free the old page
5758 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005759 kfree(ioc->raid_data.pIocPg3);
5760 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005761
5762 /* There is at least one physical disk.
5763 * Read and save IOC Page 3
5764 */
5765 header.PageVersion = 0;
5766 header.PageLength = 0;
5767 header.PageNumber = 3;
5768 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005769 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770 cfg.physAddr = -1;
5771 cfg.pageAddr = 0;
5772 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5773 cfg.dir = 0;
5774 cfg.timeout = 0;
5775 if (mpt_config(ioc, &cfg) != 0)
5776 return 0;
5777
5778 if (header.PageLength == 0)
5779 return 0;
5780
5781 /* Read Header good, alloc memory
5782 */
5783 iocpage3sz = header.PageLength * 4;
5784 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5785 if (!pIoc3)
5786 return 0;
5787
5788 /* Read the Page and save the data
5789 * into malloc'd memory.
5790 */
5791 cfg.physAddr = ioc3_dma;
5792 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5793 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005794 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795 if (mem) {
5796 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005797 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798 }
5799 }
5800
5801 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5802
5803 return 0;
5804}
5805
5806static void
5807mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5808{
5809 IOCPage4_t *pIoc4;
5810 CONFIGPARMS cfg;
5811 ConfigPageHeader_t header;
5812 dma_addr_t ioc4_dma;
5813 int iocpage4sz;
5814
5815 /* Read and save IOC Page 4
5816 */
5817 header.PageVersion = 0;
5818 header.PageLength = 0;
5819 header.PageNumber = 4;
5820 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005821 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822 cfg.physAddr = -1;
5823 cfg.pageAddr = 0;
5824 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5825 cfg.dir = 0;
5826 cfg.timeout = 0;
5827 if (mpt_config(ioc, &cfg) != 0)
5828 return;
5829
5830 if (header.PageLength == 0)
5831 return;
5832
5833 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5834 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5835 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5836 if (!pIoc4)
5837 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005838 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005839 } else {
5840 ioc4_dma = ioc->spi_data.IocPg4_dma;
5841 iocpage4sz = ioc->spi_data.IocPg4Sz;
5842 }
5843
5844 /* Read the Page into dma memory.
5845 */
5846 cfg.physAddr = ioc4_dma;
5847 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5848 if (mpt_config(ioc, &cfg) == 0) {
5849 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5850 ioc->spi_data.IocPg4_dma = ioc4_dma;
5851 ioc->spi_data.IocPg4Sz = iocpage4sz;
5852 } else {
5853 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5854 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005855 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005856 }
5857}
5858
5859static void
5860mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5861{
5862 IOCPage1_t *pIoc1;
5863 CONFIGPARMS cfg;
5864 ConfigPageHeader_t header;
5865 dma_addr_t ioc1_dma;
5866 int iocpage1sz = 0;
5867 u32 tmp;
5868
5869 /* Check the Coalescing Timeout in IOC Page 1
5870 */
5871 header.PageVersion = 0;
5872 header.PageLength = 0;
5873 header.PageNumber = 1;
5874 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005875 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876 cfg.physAddr = -1;
5877 cfg.pageAddr = 0;
5878 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5879 cfg.dir = 0;
5880 cfg.timeout = 0;
5881 if (mpt_config(ioc, &cfg) != 0)
5882 return;
5883
5884 if (header.PageLength == 0)
5885 return;
5886
5887 /* Read Header good, alloc memory
5888 */
5889 iocpage1sz = header.PageLength * 4;
5890 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5891 if (!pIoc1)
5892 return;
5893
5894 /* Read the Page and check coalescing timeout
5895 */
5896 cfg.physAddr = ioc1_dma;
5897 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5898 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305899
Linus Torvalds1da177e2005-04-16 15:20:36 -07005900 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5901 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5902 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5903
Prakash, Sathya436ace72007-07-24 15:42:08 +05305904 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005905 ioc->name, tmp));
5906
5907 if (tmp > MPT_COALESCING_TIMEOUT) {
5908 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5909
5910 /* Write NVRAM and current
5911 */
5912 cfg.dir = 1;
5913 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5914 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305915 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005916 ioc->name, MPT_COALESCING_TIMEOUT));
5917
5918 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5919 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305920 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5921 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005922 ioc->name, MPT_COALESCING_TIMEOUT));
5923 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305924 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5925 "Reset NVRAM Coalescing Timeout Failed\n",
5926 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005927 }
5928
5929 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305930 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5931 "Reset of Current Coalescing Timeout Failed!\n",
5932 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005933 }
5934 }
5935
5936 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305937 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005938 }
5939 }
5940
5941 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5942
5943 return;
5944}
5945
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305946static void
5947mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5948{
5949 CONFIGPARMS cfg;
5950 ConfigPageHeader_t hdr;
5951 dma_addr_t buf_dma;
5952 ManufacturingPage0_t *pbuf = NULL;
5953
5954 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5955 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5956
5957 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5958 cfg.cfghdr.hdr = &hdr;
5959 cfg.physAddr = -1;
5960 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5961 cfg.timeout = 10;
5962
5963 if (mpt_config(ioc, &cfg) != 0)
5964 goto out;
5965
5966 if (!cfg.cfghdr.hdr->PageLength)
5967 goto out;
5968
5969 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5970 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5971 if (!pbuf)
5972 goto out;
5973
5974 cfg.physAddr = buf_dma;
5975
5976 if (mpt_config(ioc, &cfg) != 0)
5977 goto out;
5978
5979 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5980 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5981 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5982
5983 out:
5984
5985 if (pbuf)
5986 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5987}
5988
Linus Torvalds1da177e2005-04-16 15:20:36 -07005989/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005990/**
5991 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992 * @ioc: Pointer to MPT_ADAPTER structure
5993 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05305994 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995 */
5996static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05305997SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005998{
Kashyap, Desaifd761752009-05-29 16:39:06 +05305999 EventNotification_t evn;
6000 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006001
Kashyap, Desaifd761752009-05-29 16:39:06 +05306002 memset(&evn, 0, sizeof(EventNotification_t));
6003 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006004
Kashyap, Desaifd761752009-05-29 16:39:06 +05306005 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
6006 evn.Switch = EvSwitch;
6007 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006008
Kashyap, Desaifd761752009-05-29 16:39:06 +05306009 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6010 "Sending EventNotification (%d) request %p\n",
6011 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006012
Kashyap, Desaifd761752009-05-29 16:39:06 +05306013 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6014 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6015 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006016}
6017
6018/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6019/**
6020 * SendEventAck - Send EventAck request to MPT adapter.
6021 * @ioc: Pointer to MPT_ADAPTER structure
6022 * @evnp: Pointer to original EventNotification request
6023 */
6024static int
6025SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6026{
6027 EventAck_t *pAck;
6028
6029 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306030 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306031 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006032 return -1;
6033 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006034
Prakash, Sathya436ace72007-07-24 15:42:08 +05306035 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006036
6037 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6038 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006039 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006040 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006041 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006042 pAck->Event = evnp->Event;
6043 pAck->EventContext = evnp->EventContext;
6044
6045 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6046
6047 return 0;
6048}
6049
6050/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6051/**
6052 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006053 * @ioc: Pointer to an adapter structure
6054 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006055 * action, page address, direction, physical address
6056 * and pointer to a configuration page header
6057 * Page header is updated.
6058 *
6059 * Returns 0 for success
6060 * -EPERM if not allowed due to ISR context
6061 * -EAGAIN if no msg frames currently available
6062 * -EFAULT for non-successful reply or no reply (timeout)
6063 */
6064int
6065mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6066{
6067 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306068 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006069 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306071 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006072 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306073 long timeout;
6074 int ret;
6075 u8 page_type = 0, extend_page;
6076 unsigned long timeleft;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306078 u8 issue_hard_reset = 0;
6079 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006080
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006081 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006082 * to be in ISR context, because that is fatal!
6083 */
6084 in_isr = in_interrupt();
6085 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306086 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006087 ioc->name));
6088 return -EPERM;
6089 }
6090
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306091 /* don't send if no chance of success */
6092 if (!ioc->active ||
6093 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6094 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6095 "%s: ioc not operational, %d, %xh\n",
6096 ioc->name, __func__, ioc->active,
6097 mpt_GetIocState(ioc, 0)));
6098 return -EFAULT;
6099 }
6100
6101 retry_config:
6102 mutex_lock(&ioc->mptbase_cmds.mutex);
6103 /* init the internal cmd struct */
6104 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6105 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6106
Linus Torvalds1da177e2005-04-16 15:20:36 -07006107 /* Get and Populate a free Frame
6108 */
6109 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306110 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6111 "mpt_config: no msg frames!\n", ioc->name));
6112 ret = -EAGAIN;
6113 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006114 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306115
Linus Torvalds1da177e2005-04-16 15:20:36 -07006116 pReq = (Config_t *)mf;
6117 pReq->Action = pCfg->action;
6118 pReq->Reserved = 0;
6119 pReq->ChainOffset = 0;
6120 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006121
6122 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006123 pReq->ExtPageLength = 0;
6124 pReq->ExtPageType = 0;
6125 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006126
Linus Torvalds1da177e2005-04-16 15:20:36 -07006127 for (ii=0; ii < 8; ii++)
6128 pReq->Reserved2[ii] = 0;
6129
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006130 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6131 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6132 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6133 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6134
6135 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6136 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6137 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6138 pReq->ExtPageType = pExtHdr->ExtPageType;
6139 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6140
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306141 /* Page Length must be treated as a reserved field for the
6142 * extended header.
6143 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006144 pReq->Header.PageLength = 0;
6145 }
6146
Linus Torvalds1da177e2005-04-16 15:20:36 -07006147 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6148
6149 /* Add a SGE to the config request.
6150 */
6151 if (pCfg->dir)
6152 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6153 else
6154 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6155
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306156 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6157 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006158 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306159 page_type = pReq->ExtPageType;
6160 extend_page = 1;
6161 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006162 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306163 page_type = pReq->Header.PageType;
6164 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006166
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306167 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6168 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6169 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6170
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306171 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306172 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006173 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306174 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6175 timeout);
6176 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6177 ret = -ETIME;
6178 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6179 "Failed Sending Config request type 0x%x, page 0x%x,"
6180 " action %d, status %xh, time left %ld\n\n",
6181 ioc->name, page_type, pReq->Header.PageNumber,
6182 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6183 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6184 goto out;
6185 if (!timeleft)
6186 issue_hard_reset = 1;
6187 goto out;
6188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006189
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306190 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6191 ret = -1;
6192 goto out;
6193 }
6194 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6195 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6196 if (ret == MPI_IOCSTATUS_SUCCESS) {
6197 if (extend_page) {
6198 pCfg->cfghdr.ehdr->ExtPageLength =
6199 le16_to_cpu(pReply->ExtPageLength);
6200 pCfg->cfghdr.ehdr->ExtPageType =
6201 pReply->ExtPageType;
6202 }
6203 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6204 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6205 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6206 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006207
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306208 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006209
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306210 if (retry_count)
6211 printk(MYIOC_s_INFO_FMT "Retry completed "
6212 "ret=0x%x timeleft=%ld\n",
6213 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006214
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306215 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6216 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306218out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306220 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6221 mutex_unlock(&ioc->mptbase_cmds.mutex);
6222 if (issue_hard_reset) {
6223 issue_hard_reset = 0;
6224 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
6225 ioc->name, __func__);
6226 mpt_HardResetHandler(ioc, CAN_SLEEP);
6227 mpt_free_msg_frame(ioc, mf);
6228 /* attempt one retry for a timed out command */
6229 if (!retry_count) {
6230 printk(MYIOC_s_INFO_FMT
6231 "Attempting Retry Config request"
6232 " type 0x%x, page 0x%x,"
6233 " action %d\n", ioc->name, page_type,
6234 pCfg->cfghdr.hdr->PageNumber, pCfg->action);
6235 retry_count++;
6236 goto retry_config;
6237 }
6238 }
6239 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006240
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241}
6242
6243/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006244/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006245 * mpt_ioc_reset - Base cleanup for hard reset
6246 * @ioc: Pointer to the adapter structure
6247 * @reset_phase: Indicates pre- or post-reset functionality
6248 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006249 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006250 */
6251static int
6252mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6253{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306254 switch (reset_phase) {
6255 case MPT_IOC_SETUP_RESET:
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306256 ioc->taskmgmt_quiesce_io = 1;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306257 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6258 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
6259 break;
6260 case MPT_IOC_PRE_RESET:
6261 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6262 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
6263 break;
6264 case MPT_IOC_POST_RESET:
6265 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6266 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
6267/* wake up mptbase_cmds */
6268 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6269 ioc->mptbase_cmds.status |=
6270 MPT_MGMT_STATUS_DID_IOCRESET;
6271 complete(&ioc->mptbase_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006272 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306273 break;
6274 default:
6275 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006276 }
6277
6278 return 1; /* currently means nothing really */
6279}
6280
6281
6282#ifdef CONFIG_PROC_FS /* { */
6283/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6284/*
6285 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6286 */
6287/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006288/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006289 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6290 *
6291 * Returns 0 for success, non-zero for failure.
6292 */
6293static int
6294procmpt_create(void)
6295{
6296 struct proc_dir_entry *ent;
6297
6298 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6299 if (mpt_proc_root_dir == NULL)
6300 return -ENOTDIR;
6301
6302 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6303 if (ent)
6304 ent->read_proc = procmpt_summary_read;
6305
6306 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6307 if (ent)
6308 ent->read_proc = procmpt_version_read;
6309
6310 return 0;
6311}
6312
6313/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006314/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006315 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6316 *
6317 * Returns 0 for success, non-zero for failure.
6318 */
6319static void
6320procmpt_destroy(void)
6321{
6322 remove_proc_entry("version", mpt_proc_root_dir);
6323 remove_proc_entry("summary", mpt_proc_root_dir);
6324 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6325}
6326
6327/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006328/**
6329 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006330 * @buf: Pointer to area to write information
6331 * @start: Pointer to start pointer
6332 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006333 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006334 * @eof: Pointer to EOF integer
6335 * @data: Pointer
6336 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006337 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338 * Returns number of characters written to process performing the read.
6339 */
6340static int
6341procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6342{
6343 MPT_ADAPTER *ioc;
6344 char *out = buf;
6345 int len;
6346
6347 if (data) {
6348 int more = 0;
6349
6350 ioc = data;
6351 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6352
6353 out += more;
6354 } else {
6355 list_for_each_entry(ioc, &ioc_list, list) {
6356 int more = 0;
6357
6358 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6359
6360 out += more;
6361 if ((out-buf) >= request)
6362 break;
6363 }
6364 }
6365
6366 len = out - buf;
6367
6368 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6369}
6370
6371/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006372/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006373 * procmpt_version_read - Handle read request from /proc/mpt/version.
6374 * @buf: Pointer to area to write information
6375 * @start: Pointer to start pointer
6376 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006377 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006378 * @eof: Pointer to EOF integer
6379 * @data: Pointer
6380 *
6381 * Returns number of characters written to process performing the read.
6382 */
6383static int
6384procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6385{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306386 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006387 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006388 char *drvname;
6389 int len;
6390
6391 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6392 len += sprintf(buf+len, " Fusion MPT base driver\n");
6393
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006394 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006395 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006396 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306397 if (MptCallbacks[cb_idx]) {
6398 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006399 case MPTSPI_DRIVER:
6400 if (!scsi++) drvname = "SPI host";
6401 break;
6402 case MPTFC_DRIVER:
6403 if (!fc++) drvname = "FC host";
6404 break;
6405 case MPTSAS_DRIVER:
6406 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006407 break;
6408 case MPTLAN_DRIVER:
6409 if (!lan++) drvname = "LAN";
6410 break;
6411 case MPTSTM_DRIVER:
6412 if (!targ++) drvname = "SCSI target";
6413 break;
6414 case MPTCTL_DRIVER:
6415 if (!ctl++) drvname = "ioctl";
6416 break;
6417 }
6418
6419 if (drvname)
6420 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6421 }
6422 }
6423
6424 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6425}
6426
6427/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006428/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006429 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6430 * @buf: Pointer to area to write information
6431 * @start: Pointer to start pointer
6432 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006433 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006434 * @eof: Pointer to EOF integer
6435 * @data: Pointer
6436 *
6437 * Returns number of characters written to process performing the read.
6438 */
6439static int
6440procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6441{
6442 MPT_ADAPTER *ioc = data;
6443 int len;
6444 char expVer[32];
6445 int sz;
6446 int p;
6447
6448 mpt_get_fw_exp_ver(expVer, ioc);
6449
6450 len = sprintf(buf, "%s:", ioc->name);
6451 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6452 len += sprintf(buf+len, " (f/w download boot flag set)");
6453// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6454// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6455
6456 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6457 ioc->facts.ProductID,
6458 ioc->prod_name);
6459 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6460 if (ioc->facts.FWImageSize)
6461 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6462 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6463 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6464 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6465
6466 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6467 ioc->facts.CurrentHostMfaHighAddr);
6468 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6469 ioc->facts.CurrentSenseBufferHighAddr);
6470
6471 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6472 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6473
6474 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6475 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6476 /*
6477 * Rounding UP to nearest 4-kB boundary here...
6478 */
6479 sz = (ioc->req_sz * ioc->req_depth) + 128;
6480 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6481 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6482 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6483 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6484 4*ioc->facts.RequestFrameSize,
6485 ioc->facts.GlobalCredits);
6486
6487 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6488 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6489 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6490 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6491 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6492 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6493 ioc->facts.CurReplyFrameSize,
6494 ioc->facts.ReplyQueueDepth);
6495
6496 len += sprintf(buf+len, " MaxDevices = %d\n",
6497 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6498 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6499
6500 /* per-port info */
6501 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6502 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6503 p+1,
6504 ioc->facts.NumberOfPorts);
6505 if (ioc->bus_type == FC) {
6506 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6507 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6508 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6509 a[5], a[4], a[3], a[2], a[1], a[0]);
6510 }
6511 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6512 ioc->fc_port_page0[p].WWNN.High,
6513 ioc->fc_port_page0[p].WWNN.Low,
6514 ioc->fc_port_page0[p].WWPN.High,
6515 ioc->fc_port_page0[p].WWPN.Low);
6516 }
6517 }
6518
6519 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6520}
6521
6522#endif /* CONFIG_PROC_FS } */
6523
6524/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6525static void
6526mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6527{
6528 buf[0] ='\0';
6529 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6530 sprintf(buf, " (Exp %02d%02d)",
6531 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6532 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6533
6534 /* insider hack! */
6535 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6536 strcat(buf, " [MDBG]");
6537 }
6538}
6539
6540/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6541/**
6542 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6543 * @ioc: Pointer to MPT_ADAPTER structure
6544 * @buffer: Pointer to buffer where IOC summary info should be written
6545 * @size: Pointer to number of bytes we wrote (set by this routine)
6546 * @len: Offset at which to start writing in buffer
6547 * @showlan: Display LAN stuff?
6548 *
6549 * This routine writes (english readable) ASCII text, which represents
6550 * a summary of IOC information, to a buffer.
6551 */
6552void
6553mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6554{
6555 char expVer[32];
6556 int y;
6557
6558 mpt_get_fw_exp_ver(expVer, ioc);
6559
6560 /*
6561 * Shorter summary of attached ioc's...
6562 */
6563 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6564 ioc->name,
6565 ioc->prod_name,
6566 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6567 ioc->facts.FWVersion.Word,
6568 expVer,
6569 ioc->facts.NumberOfPorts,
6570 ioc->req_depth);
6571
6572 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6573 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6574 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6575 a[5], a[4], a[3], a[2], a[1], a[0]);
6576 }
6577
Linus Torvalds1da177e2005-04-16 15:20:36 -07006578 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006579
6580 if (!ioc->active)
6581 y += sprintf(buffer+len+y, " (disabled)");
6582
6583 y += sprintf(buffer+len+y, "\n");
6584
6585 *size = y;
6586}
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306587/**
6588 * mpt_set_taskmgmt_in_progress_flag - set flags associated with task managment
6589 * @ioc: Pointer to MPT_ADAPTER structure
6590 *
6591 * Returns 0 for SUCCESS or -1 if FAILED.
6592 *
6593 * If -1 is return, then it was not possible to set the flags
6594 **/
6595int
6596mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6597{
6598 unsigned long flags;
6599 int retval;
6600
6601 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6602 if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
6603 (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
6604 retval = -1;
6605 goto out;
6606 }
6607 retval = 0;
6608 ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306609 ioc->taskmgmt_quiesce_io = 1;
6610 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306611 ioc->alt_ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306612 ioc->alt_ioc->taskmgmt_quiesce_io = 1;
6613 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306614 out:
6615 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6616 return retval;
6617}
6618EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
6619
6620/**
6621 * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task managment
6622 * @ioc: Pointer to MPT_ADAPTER structure
6623 *
6624 **/
6625void
6626mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6627{
6628 unsigned long flags;
6629
6630 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6631 ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306632 ioc->taskmgmt_quiesce_io = 0;
6633 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306634 ioc->alt_ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306635 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
6636 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306637 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6638}
6639EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006640
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306641
6642/**
6643 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6644 * the kernel
6645 * @ioc: Pointer to MPT_ADAPTER structure
6646 *
6647 **/
6648void
6649mpt_halt_firmware(MPT_ADAPTER *ioc)
6650{
6651 u32 ioc_raw_state;
6652
6653 ioc_raw_state = mpt_GetIocState(ioc, 0);
6654
6655 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6656 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6657 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6658 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6659 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6660 } else {
6661 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6662 panic("%s: Firmware is halted due to command timeout\n",
6663 ioc->name);
6664 }
6665}
6666EXPORT_SYMBOL(mpt_halt_firmware);
6667
Linus Torvalds1da177e2005-04-16 15:20:36 -07006668/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6669/*
6670 * Reset Handling
6671 */
6672/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6673/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006674 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006675 * @ioc: Pointer to MPT_ADAPTER structure
6676 * @sleepFlag: Indicates if sleep or schedule must be called.
6677 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006678 * Issues SCSI Task Management call based on input arg values.
6679 * If TaskMgmt fails, returns associated SCSI request.
6680 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006681 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6682 * or a non-interrupt thread. In the former, must not call schedule().
6683 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006684 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006685 * FW reload/initialization failed.
6686 *
6687 * Returns 0 for SUCCESS or -1 if FAILED.
6688 */
6689int
6690mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6691{
6692 int rc;
6693 unsigned long flags;
6694
Prakash, Sathya436ace72007-07-24 15:42:08 +05306695 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006696#ifdef MFCNT
6697 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6698 printk("MF count 0x%x !\n", ioc->mfcnt);
6699#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306700 if (mpt_fwfault_debug)
6701 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006702
6703 /* Reset the adapter. Prevent more than 1 call to
6704 * mpt_do_ioc_recovery at any instant in time.
6705 */
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306706 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6707 if (ioc->ioc_reset_in_progress) {
6708 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006709 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006710 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306711 ioc->ioc_reset_in_progress = 1;
6712 if (ioc->alt_ioc)
6713 ioc->alt_ioc->ioc_reset_in_progress = 1;
6714 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006715
6716 /* FIXME: If do_ioc_recovery fails, repeat....
6717 */
6718
6719 /* The SCSI driver needs to adjust timeouts on all current
6720 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006721 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006722 * For all other protocol drivers, this is a no-op.
6723 */
6724 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306725 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006726 int r = 0;
6727
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306728 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6729 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306730 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306731 ioc->name, cb_idx));
6732 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006733 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306734 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306735 ioc->name, ioc->alt_ioc->name, cb_idx));
6736 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006737 }
6738 }
6739 }
6740 }
6741
6742 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06006743 printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006744 }
6745 ioc->reload_fw = 0;
6746 if (ioc->alt_ioc)
6747 ioc->alt_ioc->reload_fw = 0;
6748
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306749 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6750 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306751 ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306752 ioc->taskmgmt_in_progress = 0;
6753 if (ioc->alt_ioc) {
6754 ioc->alt_ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306755 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306756 ioc->alt_ioc->taskmgmt_in_progress = 0;
6757 }
6758 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006759
Prakash, Sathya436ace72007-07-24 15:42:08 +05306760 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006761
6762 return rc;
6763}
6764
6765/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006766static void
6767EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006768{
Eric Moore509e5e52006-04-26 13:22:37 -06006769 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006770
6771 switch(event) {
6772 case MPI_EVENT_NONE:
6773 ds = "None";
6774 break;
6775 case MPI_EVENT_LOG_DATA:
6776 ds = "Log Data";
6777 break;
6778 case MPI_EVENT_STATE_CHANGE:
6779 ds = "State Change";
6780 break;
6781 case MPI_EVENT_UNIT_ATTENTION:
6782 ds = "Unit Attention";
6783 break;
6784 case MPI_EVENT_IOC_BUS_RESET:
6785 ds = "IOC Bus Reset";
6786 break;
6787 case MPI_EVENT_EXT_BUS_RESET:
6788 ds = "External Bus Reset";
6789 break;
6790 case MPI_EVENT_RESCAN:
6791 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006792 break;
6793 case MPI_EVENT_LINK_STATUS_CHANGE:
6794 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6795 ds = "Link Status(FAILURE) Change";
6796 else
6797 ds = "Link Status(ACTIVE) Change";
6798 break;
6799 case MPI_EVENT_LOOP_STATE_CHANGE:
6800 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6801 ds = "Loop State(LIP) Change";
6802 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006803 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006804 else
Eric Moore509e5e52006-04-26 13:22:37 -06006805 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006806 break;
6807 case MPI_EVENT_LOGOUT:
6808 ds = "Logout";
6809 break;
6810 case MPI_EVENT_EVENT_CHANGE:
6811 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006812 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006813 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006814 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006815 break;
6816 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006817 {
6818 u8 ReasonCode = (u8)(evData0 >> 16);
6819 switch (ReasonCode) {
6820 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6821 ds = "Integrated Raid: Volume Created";
6822 break;
6823 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6824 ds = "Integrated Raid: Volume Deleted";
6825 break;
6826 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6827 ds = "Integrated Raid: Volume Settings Changed";
6828 break;
6829 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6830 ds = "Integrated Raid: Volume Status Changed";
6831 break;
6832 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6833 ds = "Integrated Raid: Volume Physdisk Changed";
6834 break;
6835 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6836 ds = "Integrated Raid: Physdisk Created";
6837 break;
6838 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6839 ds = "Integrated Raid: Physdisk Deleted";
6840 break;
6841 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6842 ds = "Integrated Raid: Physdisk Settings Changed";
6843 break;
6844 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6845 ds = "Integrated Raid: Physdisk Status Changed";
6846 break;
6847 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6848 ds = "Integrated Raid: Domain Validation Needed";
6849 break;
6850 case MPI_EVENT_RAID_RC_SMART_DATA :
6851 ds = "Integrated Raid; Smart Data";
6852 break;
6853 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6854 ds = "Integrated Raid: Replace Action Started";
6855 break;
6856 default:
6857 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006858 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006859 }
6860 break;
6861 }
6862 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6863 ds = "SCSI Device Status Change";
6864 break;
6865 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6866 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006867 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006868 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006869 u8 ReasonCode = (u8)(evData0 >> 16);
6870 switch (ReasonCode) {
6871 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006872 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006873 "SAS Device Status Change: Added: "
6874 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006875 break;
6876 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006877 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006878 "SAS Device Status Change: Deleted: "
6879 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006880 break;
6881 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006882 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006883 "SAS Device Status Change: SMART Data: "
6884 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006885 break;
6886 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006887 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006888 "SAS Device Status Change: No Persistancy: "
6889 "id=%d channel=%d", id, channel);
6890 break;
6891 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6892 snprintf(evStr, EVENT_DESCR_STR_SZ,
6893 "SAS Device Status Change: Unsupported Device "
6894 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006895 break;
6896 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6897 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006898 "SAS Device Status Change: Internal Device "
6899 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006900 break;
6901 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6902 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006903 "SAS Device Status Change: Internal Task "
6904 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006905 break;
6906 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6907 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006908 "SAS Device Status Change: Internal Abort "
6909 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006910 break;
6911 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6912 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006913 "SAS Device Status Change: Internal Clear "
6914 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006915 break;
6916 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6917 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006918 "SAS Device Status Change: Internal Query "
6919 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006920 break;
6921 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006922 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006923 "SAS Device Status Change: Unknown: "
6924 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006925 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006926 }
6927 break;
6928 }
6929 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6930 ds = "Bus Timer Expired";
6931 break;
6932 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006933 {
6934 u16 curr_depth = (u16)(evData0 >> 16);
6935 u8 channel = (u8)(evData0 >> 8);
6936 u8 id = (u8)(evData0);
6937
6938 snprintf(evStr, EVENT_DESCR_STR_SZ,
6939 "Queue Full: channel=%d id=%d depth=%d",
6940 channel, id, curr_depth);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006941 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006942 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006943 case MPI_EVENT_SAS_SES:
6944 ds = "SAS SES Event";
6945 break;
6946 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6947 ds = "Persistent Table Full";
6948 break;
6949 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006950 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006951 u8 LinkRates = (u8)(evData0 >> 8);
6952 u8 PhyNumber = (u8)(evData0);
6953 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6954 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6955 switch (LinkRates) {
6956 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006957 snprintf(evStr, EVENT_DESCR_STR_SZ,
6958 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006959 " Rate Unknown",PhyNumber);
6960 break;
6961 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006962 snprintf(evStr, EVENT_DESCR_STR_SZ,
6963 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006964 " Phy Disabled",PhyNumber);
6965 break;
6966 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006967 snprintf(evStr, EVENT_DESCR_STR_SZ,
6968 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006969 " Failed Speed Nego",PhyNumber);
6970 break;
6971 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006972 snprintf(evStr, EVENT_DESCR_STR_SZ,
6973 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006974 " Sata OOB Completed",PhyNumber);
6975 break;
6976 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006977 snprintf(evStr, EVENT_DESCR_STR_SZ,
6978 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006979 " Rate 1.5 Gbps",PhyNumber);
6980 break;
6981 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006982 snprintf(evStr, EVENT_DESCR_STR_SZ,
6983 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006984 " Rate 3.0 Gpbs",PhyNumber);
6985 break;
6986 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006987 snprintf(evStr, EVENT_DESCR_STR_SZ,
6988 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006989 break;
6990 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006991 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006992 }
Christoph Hellwig82ffb672005-09-09 16:25:54 +02006993 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6994 ds = "SAS Discovery Error";
6995 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006996 case MPI_EVENT_IR_RESYNC_UPDATE:
6997 {
6998 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006999 snprintf(evStr, EVENT_DESCR_STR_SZ,
7000 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07007001 break;
7002 }
7003 case MPI_EVENT_IR2:
7004 {
7005 u8 ReasonCode = (u8)(evData0 >> 16);
7006 switch (ReasonCode) {
7007 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
7008 ds = "IR2: LD State Changed";
7009 break;
7010 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
7011 ds = "IR2: PD State Changed";
7012 break;
7013 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
7014 ds = "IR2: Bad Block Table Full";
7015 break;
7016 case MPI_EVENT_IR2_RC_PD_INSERTED:
7017 ds = "IR2: PD Inserted";
7018 break;
7019 case MPI_EVENT_IR2_RC_PD_REMOVED:
7020 ds = "IR2: PD Removed";
7021 break;
7022 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
7023 ds = "IR2: Foreign CFG Detected";
7024 break;
7025 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
7026 ds = "IR2: Rebuild Medium Error";
7027 break;
7028 default:
7029 ds = "IR2";
7030 break;
7031 }
7032 break;
7033 }
7034 case MPI_EVENT_SAS_DISCOVERY:
7035 {
7036 if (evData0)
7037 ds = "SAS Discovery: Start";
7038 else
7039 ds = "SAS Discovery: Stop";
7040 break;
7041 }
7042 case MPI_EVENT_LOG_ENTRY_ADDED:
7043 ds = "SAS Log Entry Added";
7044 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007045
Eric Moorec6c727a2007-01-29 09:44:54 -07007046 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
7047 {
7048 u8 phy_num = (u8)(evData0);
7049 u8 port_num = (u8)(evData0 >> 8);
7050 u8 port_width = (u8)(evData0 >> 16);
7051 u8 primative = (u8)(evData0 >> 24);
7052 snprintf(evStr, EVENT_DESCR_STR_SZ,
7053 "SAS Broadcase Primative: phy=%d port=%d "
7054 "width=%d primative=0x%02x",
7055 phy_num, port_num, port_width, primative);
7056 break;
7057 }
7058
7059 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7060 {
7061 u8 reason = (u8)(evData0);
7062 u8 port_num = (u8)(evData0 >> 8);
7063 u16 handle = le16_to_cpu(evData0 >> 16);
7064
7065 snprintf(evStr, EVENT_DESCR_STR_SZ,
7066 "SAS Initiator Device Status Change: reason=0x%02x "
7067 "port=%d handle=0x%04x",
7068 reason, port_num, handle);
7069 break;
7070 }
7071
7072 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7073 {
7074 u8 max_init = (u8)(evData0);
7075 u8 current_init = (u8)(evData0 >> 8);
7076
7077 snprintf(evStr, EVENT_DESCR_STR_SZ,
7078 "SAS Initiator Device Table Overflow: max initiators=%02d "
7079 "current initators=%02d",
7080 max_init, current_init);
7081 break;
7082 }
7083 case MPI_EVENT_SAS_SMP_ERROR:
7084 {
7085 u8 status = (u8)(evData0);
7086 u8 port_num = (u8)(evData0 >> 8);
7087 u8 result = (u8)(evData0 >> 16);
7088
7089 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7090 snprintf(evStr, EVENT_DESCR_STR_SZ,
7091 "SAS SMP Error: port=%d result=0x%02x",
7092 port_num, result);
7093 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7094 snprintf(evStr, EVENT_DESCR_STR_SZ,
7095 "SAS SMP Error: port=%d : CRC Error",
7096 port_num);
7097 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7098 snprintf(evStr, EVENT_DESCR_STR_SZ,
7099 "SAS SMP Error: port=%d : Timeout",
7100 port_num);
7101 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7102 snprintf(evStr, EVENT_DESCR_STR_SZ,
7103 "SAS SMP Error: port=%d : No Destination",
7104 port_num);
7105 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7106 snprintf(evStr, EVENT_DESCR_STR_SZ,
7107 "SAS SMP Error: port=%d : Bad Destination",
7108 port_num);
7109 else
7110 snprintf(evStr, EVENT_DESCR_STR_SZ,
7111 "SAS SMP Error: port=%d : status=0x%02x",
7112 port_num, status);
7113 break;
7114 }
7115
Linus Torvalds1da177e2005-04-16 15:20:36 -07007116 /*
7117 * MPT base "custom" events may be added here...
7118 */
7119 default:
7120 ds = "Unknown";
7121 break;
7122 }
Eric Moore509e5e52006-04-26 13:22:37 -06007123 if (ds)
7124 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007125}
7126
7127/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007128/**
7129 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007130 * @ioc: Pointer to MPT_ADAPTER structure
7131 * @pEventReply: Pointer to EventNotification reply frame
7132 * @evHandlers: Pointer to integer, number of event handlers
7133 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007134 * Routes a received EventNotificationReply to all currently registered
7135 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007136 * Returns sum of event handlers return values.
7137 */
7138static int
7139ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7140{
7141 u16 evDataLen;
7142 u32 evData0 = 0;
7143// u32 evCtx;
7144 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307145 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007146 int r = 0;
7147 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06007148 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007149 u8 event;
7150
7151 /*
7152 * Do platform normalization of values
7153 */
7154 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7155// evCtx = le32_to_cpu(pEventReply->EventContext);
7156 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7157 if (evDataLen) {
7158 evData0 = le32_to_cpu(pEventReply->Data[0]);
7159 }
7160
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007161 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05307162 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007163 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07007164 event,
7165 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007166
Prakash, Sathya436ace72007-07-24 15:42:08 +05307167#ifdef CONFIG_FUSION_LOGGING
Eric Moore29dd3602007-09-14 18:46:51 -06007168 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7169 ": Event data:\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007170 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05307171 devtverboseprintk(ioc, printk(" %08x",
7172 le32_to_cpu(pEventReply->Data[ii])));
Eric Moore29dd3602007-09-14 18:46:51 -06007173 devtverboseprintk(ioc, printk("\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007174#endif
7175
7176 /*
7177 * Do general / base driver event processing
7178 */
7179 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007180 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7181 if (evDataLen) {
7182 u8 evState = evData0 & 0xFF;
7183
7184 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7185
7186 /* Update EventState field in cached IocFacts */
7187 if (ioc->facts.Function) {
7188 ioc->facts.EventState = evState;
7189 }
7190 }
7191 break;
Moore, Ericece50912006-01-16 18:53:19 -07007192 case MPI_EVENT_INTEGRATED_RAID:
7193 mptbase_raid_process_event_data(ioc,
7194 (MpiEventDataRaid_t *)pEventReply->Data);
7195 break;
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007196 default:
7197 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007198 }
7199
7200 /*
7201 * Should this event be logged? Events are written sequentially.
7202 * When buffer is full, start again at the top.
7203 */
7204 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7205 int idx;
7206
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007207 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007208
7209 ioc->events[idx].event = event;
7210 ioc->events[idx].eventContext = ioc->eventContext;
7211
7212 for (ii = 0; ii < 2; ii++) {
7213 if (ii < evDataLen)
7214 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7215 else
7216 ioc->events[idx].data[ii] = 0;
7217 }
7218
7219 ioc->eventContext++;
7220 }
7221
7222
7223 /*
7224 * Call each currently registered protocol event handler.
7225 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007226 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307227 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307228 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307229 ioc->name, cb_idx));
7230 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007231 handlers++;
7232 }
7233 }
7234 /* FIXME? Examine results here? */
7235
7236 /*
7237 * If needed, send (a single) EventAck.
7238 */
7239 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307240 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007241 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007242 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307243 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007244 ioc->name, ii));
7245 }
7246 }
7247
7248 *evHandlers = handlers;
7249 return r;
7250}
7251
7252/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007253/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007254 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7255 * @ioc: Pointer to MPT_ADAPTER structure
7256 * @log_info: U32 LogInfo reply word from the IOC
7257 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007258 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007259 */
7260static void
7261mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7262{
Eric Moore7c431e52007-06-13 16:34:36 -06007263 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007264
Eric Moore7c431e52007-06-13 16:34:36 -06007265 switch (log_info & 0xFF000000) {
7266 case MPI_IOCLOGINFO_FC_INIT_BASE:
7267 desc = "FCP Initiator";
7268 break;
7269 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7270 desc = "FCP Target";
7271 break;
7272 case MPI_IOCLOGINFO_FC_LAN_BASE:
7273 desc = "LAN";
7274 break;
7275 case MPI_IOCLOGINFO_FC_MSG_BASE:
7276 desc = "MPI Message Layer";
7277 break;
7278 case MPI_IOCLOGINFO_FC_LINK_BASE:
7279 desc = "FC Link";
7280 break;
7281 case MPI_IOCLOGINFO_FC_CTX_BASE:
7282 desc = "Context Manager";
7283 break;
7284 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7285 desc = "Invalid Field Offset";
7286 break;
7287 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7288 desc = "State Change Info";
7289 break;
7290 }
7291
7292 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7293 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007294}
7295
7296/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007297/**
Moore, Eric335a9412006-01-17 17:06:23 -07007298 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007299 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007300 * @log_info: U32 LogInfo word from the IOC
7301 *
7302 * Refer to lsi/sp_log.h.
7303 */
7304static void
Moore, Eric335a9412006-01-17 17:06:23 -07007305mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007306{
7307 u32 info = log_info & 0x00FF0000;
7308 char *desc = "unknown";
7309
7310 switch (info) {
7311 case 0x00010000:
7312 desc = "bug! MID not found";
7313 if (ioc->reload_fw == 0)
7314 ioc->reload_fw++;
7315 break;
7316
7317 case 0x00020000:
7318 desc = "Parity Error";
7319 break;
7320
7321 case 0x00030000:
7322 desc = "ASYNC Outbound Overrun";
7323 break;
7324
7325 case 0x00040000:
7326 desc = "SYNC Offset Error";
7327 break;
7328
7329 case 0x00050000:
7330 desc = "BM Change";
7331 break;
7332
7333 case 0x00060000:
7334 desc = "Msg In Overflow";
7335 break;
7336
7337 case 0x00070000:
7338 desc = "DMA Error";
7339 break;
7340
7341 case 0x00080000:
7342 desc = "Outbound DMA Overrun";
7343 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007344
Linus Torvalds1da177e2005-04-16 15:20:36 -07007345 case 0x00090000:
7346 desc = "Task Management";
7347 break;
7348
7349 case 0x000A0000:
7350 desc = "Device Problem";
7351 break;
7352
7353 case 0x000B0000:
7354 desc = "Invalid Phase Change";
7355 break;
7356
7357 case 0x000C0000:
7358 desc = "Untagged Table Size";
7359 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007360
Linus Torvalds1da177e2005-04-16 15:20:36 -07007361 }
7362
7363 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7364}
7365
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007366/* strings for sas loginfo */
7367 static char *originator_str[] = {
7368 "IOP", /* 00h */
7369 "PL", /* 01h */
7370 "IR" /* 02h */
7371 };
7372 static char *iop_code_str[] = {
7373 NULL, /* 00h */
7374 "Invalid SAS Address", /* 01h */
7375 NULL, /* 02h */
7376 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007377 "Diag Message Error", /* 04h */
7378 "Task Terminated", /* 05h */
7379 "Enclosure Management", /* 06h */
7380 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007381 };
7382 static char *pl_code_str[] = {
7383 NULL, /* 00h */
7384 "Open Failure", /* 01h */
7385 "Invalid Scatter Gather List", /* 02h */
7386 "Wrong Relative Offset or Frame Length", /* 03h */
7387 "Frame Transfer Error", /* 04h */
7388 "Transmit Frame Connected Low", /* 05h */
7389 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7390 "SATA Read Log Receive Data Error", /* 07h */
7391 "SATA NCQ Fail All Commands After Error", /* 08h */
7392 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7393 "Receive Frame Invalid Message", /* 0Ah */
7394 "Receive Context Message Valid Error", /* 0Bh */
7395 "Receive Frame Current Frame Error", /* 0Ch */
7396 "SATA Link Down", /* 0Dh */
7397 "Discovery SATA Init W IOS", /* 0Eh */
7398 "Config Invalid Page", /* 0Fh */
7399 "Discovery SATA Init Timeout", /* 10h */
7400 "Reset", /* 11h */
7401 "Abort", /* 12h */
7402 "IO Not Yet Executed", /* 13h */
7403 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007404 "Persistent Reservation Out Not Affiliation "
7405 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007406 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007407 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007408 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007409 NULL, /* 19h */
7410 NULL, /* 1Ah */
7411 NULL, /* 1Bh */
7412 NULL, /* 1Ch */
7413 NULL, /* 1Dh */
7414 NULL, /* 1Eh */
7415 NULL, /* 1Fh */
7416 "Enclosure Management" /* 20h */
7417 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007418 static char *ir_code_str[] = {
7419 "Raid Action Error", /* 00h */
7420 NULL, /* 00h */
7421 NULL, /* 01h */
7422 NULL, /* 02h */
7423 NULL, /* 03h */
7424 NULL, /* 04h */
7425 NULL, /* 05h */
7426 NULL, /* 06h */
7427 NULL /* 07h */
7428 };
7429 static char *raid_sub_code_str[] = {
7430 NULL, /* 00h */
7431 "Volume Creation Failed: Data Passed too "
7432 "Large", /* 01h */
7433 "Volume Creation Failed: Duplicate Volumes "
7434 "Attempted", /* 02h */
7435 "Volume Creation Failed: Max Number "
7436 "Supported Volumes Exceeded", /* 03h */
7437 "Volume Creation Failed: DMA Error", /* 04h */
7438 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7439 "Volume Creation Failed: Error Reading "
7440 "MFG Page 4", /* 06h */
7441 "Volume Creation Failed: Creating Internal "
7442 "Structures", /* 07h */
7443 NULL, /* 08h */
7444 NULL, /* 09h */
7445 NULL, /* 0Ah */
7446 NULL, /* 0Bh */
7447 NULL, /* 0Ch */
7448 NULL, /* 0Dh */
7449 NULL, /* 0Eh */
7450 NULL, /* 0Fh */
7451 "Activation failed: Already Active Volume", /* 10h */
7452 "Activation failed: Unsupported Volume Type", /* 11h */
7453 "Activation failed: Too Many Active Volumes", /* 12h */
7454 "Activation failed: Volume ID in Use", /* 13h */
7455 "Activation failed: Reported Failure", /* 14h */
7456 "Activation failed: Importing a Volume", /* 15h */
7457 NULL, /* 16h */
7458 NULL, /* 17h */
7459 NULL, /* 18h */
7460 NULL, /* 19h */
7461 NULL, /* 1Ah */
7462 NULL, /* 1Bh */
7463 NULL, /* 1Ch */
7464 NULL, /* 1Dh */
7465 NULL, /* 1Eh */
7466 NULL, /* 1Fh */
7467 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7468 "Phys Disk failed: Data Passed too Large", /* 21h */
7469 "Phys Disk failed: DMA Error", /* 22h */
7470 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7471 "Phys Disk failed: Creating Phys Disk Config "
7472 "Page", /* 24h */
7473 NULL, /* 25h */
7474 NULL, /* 26h */
7475 NULL, /* 27h */
7476 NULL, /* 28h */
7477 NULL, /* 29h */
7478 NULL, /* 2Ah */
7479 NULL, /* 2Bh */
7480 NULL, /* 2Ch */
7481 NULL, /* 2Dh */
7482 NULL, /* 2Eh */
7483 NULL, /* 2Fh */
7484 "Compatibility Error: IR Disabled", /* 30h */
7485 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7486 "Compatibility Error: Device not Direct Access "
7487 "Device ", /* 32h */
7488 "Compatibility Error: Removable Device Found", /* 33h */
7489 "Compatibility Error: Device SCSI Version not "
7490 "2 or Higher", /* 34h */
7491 "Compatibility Error: SATA Device, 48 BIT LBA "
7492 "not Supported", /* 35h */
7493 "Compatibility Error: Device doesn't have "
7494 "512 Byte Block Sizes", /* 36h */
7495 "Compatibility Error: Volume Type Check Failed", /* 37h */
7496 "Compatibility Error: Volume Type is "
7497 "Unsupported by FW", /* 38h */
7498 "Compatibility Error: Disk Drive too Small for "
7499 "use in Volume", /* 39h */
7500 "Compatibility Error: Phys Disk for Create "
7501 "Volume not Found", /* 3Ah */
7502 "Compatibility Error: Too Many or too Few "
7503 "Disks for Volume Type", /* 3Bh */
7504 "Compatibility Error: Disk stripe Sizes "
7505 "Must be 64KB", /* 3Ch */
7506 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7507 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007508
7509/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007510/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007511 * mpt_sas_log_info - Log information returned from SAS IOC.
7512 * @ioc: Pointer to MPT_ADAPTER structure
7513 * @log_info: U32 LogInfo reply word from the IOC
7514 *
7515 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007516 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007517static void
7518mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7519{
7520union loginfo_type {
7521 u32 loginfo;
7522 struct {
7523 u32 subcode:16;
7524 u32 code:8;
7525 u32 originator:4;
7526 u32 bus_type:4;
7527 }dw;
7528};
7529 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007530 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007531 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007532 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007533
7534 sas_loginfo.loginfo = log_info;
7535 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007536 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007537 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007538
7539 originator_desc = originator_str[sas_loginfo.dw.originator];
7540
7541 switch (sas_loginfo.dw.originator) {
7542
7543 case 0: /* IOP */
7544 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007545 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007546 code_desc = iop_code_str[sas_loginfo.dw.code];
7547 break;
7548 case 1: /* PL */
7549 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007550 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007551 code_desc = pl_code_str[sas_loginfo.dw.code];
7552 break;
7553 case 2: /* IR */
7554 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007555 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007556 break;
7557 code_desc = ir_code_str[sas_loginfo.dw.code];
7558 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007559 ARRAY_SIZE(raid_sub_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007560 break;
7561 if (sas_loginfo.dw.code == 0)
7562 sub_code_desc =
7563 raid_sub_code_str[sas_loginfo.dw.subcode];
7564 break;
7565 default:
7566 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007567 }
7568
Eric Moorec6c727a2007-01-29 09:44:54 -07007569 if (sub_code_desc != NULL)
7570 printk(MYIOC_s_INFO_FMT
7571 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7572 " SubCode={%s}\n",
7573 ioc->name, log_info, originator_desc, code_desc,
7574 sub_code_desc);
7575 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007576 printk(MYIOC_s_INFO_FMT
7577 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7578 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007579 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007580 sas_loginfo.dw.subcode);
7581 else
7582 printk(MYIOC_s_INFO_FMT
7583 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7584 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007585 ioc->name, log_info, originator_desc,
7586 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007587}
7588
Linus Torvalds1da177e2005-04-16 15:20:36 -07007589/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007590/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007591 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7592 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007593 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007594 * @mf: Pointer to MPT request frame
7595 *
7596 * Refer to lsi/mpi.h.
7597 **/
7598static void
7599mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7600{
7601 Config_t *pReq = (Config_t *)mf;
7602 char extend_desc[EVENT_DESCR_STR_SZ];
7603 char *desc = NULL;
7604 u32 form;
7605 u8 page_type;
7606
7607 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7608 page_type = pReq->ExtPageType;
7609 else
7610 page_type = pReq->Header.PageType;
7611
7612 /*
7613 * ignore invalid page messages for GET_NEXT_HANDLE
7614 */
7615 form = le32_to_cpu(pReq->PageAddress);
7616 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7617 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7618 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7619 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7620 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7621 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7622 return;
7623 }
7624 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7625 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7626 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7627 return;
7628 }
7629
7630 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7631 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7632 page_type, pReq->Header.PageNumber, pReq->Action, form);
7633
7634 switch (ioc_status) {
7635
7636 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7637 desc = "Config Page Invalid Action";
7638 break;
7639
7640 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7641 desc = "Config Page Invalid Type";
7642 break;
7643
7644 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7645 desc = "Config Page Invalid Page";
7646 break;
7647
7648 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7649 desc = "Config Page Invalid Data";
7650 break;
7651
7652 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7653 desc = "Config Page No Defaults";
7654 break;
7655
7656 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7657 desc = "Config Page Can't Commit";
7658 break;
7659 }
7660
7661 if (!desc)
7662 return;
7663
Eric Moore29dd3602007-09-14 18:46:51 -06007664 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7665 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007666}
7667
7668/**
7669 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007670 * @ioc: Pointer to MPT_ADAPTER structure
7671 * @ioc_status: U32 IOCStatus word from IOC
7672 * @mf: Pointer to MPT request frame
7673 *
7674 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007675 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007676static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007677mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007678{
7679 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007680 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007681
7682 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007683
7684/****************************************************************************/
7685/* Common IOCStatus values for all replies */
7686/****************************************************************************/
7687
Linus Torvalds1da177e2005-04-16 15:20:36 -07007688 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7689 desc = "Invalid Function";
7690 break;
7691
7692 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7693 desc = "Busy";
7694 break;
7695
7696 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7697 desc = "Invalid SGL";
7698 break;
7699
7700 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7701 desc = "Internal Error";
7702 break;
7703
7704 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7705 desc = "Reserved";
7706 break;
7707
7708 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7709 desc = "Insufficient Resources";
7710 break;
7711
7712 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7713 desc = "Invalid Field";
7714 break;
7715
7716 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7717 desc = "Invalid State";
7718 break;
7719
Eric Moorec6c727a2007-01-29 09:44:54 -07007720/****************************************************************************/
7721/* Config IOCStatus values */
7722/****************************************************************************/
7723
Linus Torvalds1da177e2005-04-16 15:20:36 -07007724 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7725 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7726 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7727 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7728 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7729 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007730 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007731 break;
7732
Eric Moorec6c727a2007-01-29 09:44:54 -07007733/****************************************************************************/
7734/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7735/* */
7736/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7737/* */
7738/****************************************************************************/
7739
Linus Torvalds1da177e2005-04-16 15:20:36 -07007740 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007741 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007742 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7743 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7744 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7745 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007746 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007747 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007748 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007749 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007750 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007751 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007752 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007753 break;
7754
Eric Moorec6c727a2007-01-29 09:44:54 -07007755/****************************************************************************/
7756/* SCSI Target values */
7757/****************************************************************************/
7758
7759 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7760 desc = "Target: Priority IO";
7761 break;
7762
7763 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7764 desc = "Target: Invalid Port";
7765 break;
7766
7767 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7768 desc = "Target Invalid IO Index:";
7769 break;
7770
7771 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7772 desc = "Target: Aborted";
7773 break;
7774
7775 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7776 desc = "Target: No Conn Retryable";
7777 break;
7778
7779 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7780 desc = "Target: No Connection";
7781 break;
7782
7783 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7784 desc = "Target: Transfer Count Mismatch";
7785 break;
7786
7787 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7788 desc = "Target: STS Data not Sent";
7789 break;
7790
7791 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7792 desc = "Target: Data Offset Error";
7793 break;
7794
7795 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7796 desc = "Target: Too Much Write Data";
7797 break;
7798
7799 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7800 desc = "Target: IU Too Short";
7801 break;
7802
7803 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7804 desc = "Target: ACK NAK Timeout";
7805 break;
7806
7807 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7808 desc = "Target: Nak Received";
7809 break;
7810
7811/****************************************************************************/
7812/* Fibre Channel Direct Access values */
7813/****************************************************************************/
7814
7815 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7816 desc = "FC: Aborted";
7817 break;
7818
7819 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7820 desc = "FC: RX ID Invalid";
7821 break;
7822
7823 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7824 desc = "FC: DID Invalid";
7825 break;
7826
7827 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7828 desc = "FC: Node Logged Out";
7829 break;
7830
7831 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7832 desc = "FC: Exchange Canceled";
7833 break;
7834
7835/****************************************************************************/
7836/* LAN values */
7837/****************************************************************************/
7838
7839 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7840 desc = "LAN: Device not Found";
7841 break;
7842
7843 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7844 desc = "LAN: Device Failure";
7845 break;
7846
7847 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7848 desc = "LAN: Transmit Error";
7849 break;
7850
7851 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7852 desc = "LAN: Transmit Aborted";
7853 break;
7854
7855 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7856 desc = "LAN: Receive Error";
7857 break;
7858
7859 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7860 desc = "LAN: Receive Aborted";
7861 break;
7862
7863 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7864 desc = "LAN: Partial Packet";
7865 break;
7866
7867 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7868 desc = "LAN: Canceled";
7869 break;
7870
7871/****************************************************************************/
7872/* Serial Attached SCSI values */
7873/****************************************************************************/
7874
7875 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7876 desc = "SAS: SMP Request Failed";
7877 break;
7878
7879 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7880 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007881 break;
7882
7883 default:
7884 desc = "Others";
7885 break;
7886 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007887
7888 if (!desc)
7889 return;
7890
Eric Moore29dd3602007-09-14 18:46:51 -06007891 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
7892 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007893}
7894
7895/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007896EXPORT_SYMBOL(mpt_attach);
7897EXPORT_SYMBOL(mpt_detach);
7898#ifdef CONFIG_PM
7899EXPORT_SYMBOL(mpt_resume);
7900EXPORT_SYMBOL(mpt_suspend);
7901#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007902EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007903EXPORT_SYMBOL(mpt_register);
7904EXPORT_SYMBOL(mpt_deregister);
7905EXPORT_SYMBOL(mpt_event_register);
7906EXPORT_SYMBOL(mpt_event_deregister);
7907EXPORT_SYMBOL(mpt_reset_register);
7908EXPORT_SYMBOL(mpt_reset_deregister);
7909EXPORT_SYMBOL(mpt_device_driver_register);
7910EXPORT_SYMBOL(mpt_device_driver_deregister);
7911EXPORT_SYMBOL(mpt_get_msg_frame);
7912EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307913EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007914EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007915EXPORT_SYMBOL(mpt_send_handshake_request);
7916EXPORT_SYMBOL(mpt_verify_adapter);
7917EXPORT_SYMBOL(mpt_GetIocState);
7918EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007919EXPORT_SYMBOL(mpt_HardResetHandler);
7920EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007921EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007922EXPORT_SYMBOL(mpt_alloc_fw_memory);
7923EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb672005-09-09 16:25:54 +02007924EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007925EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007926
Linus Torvalds1da177e2005-04-16 15:20:36 -07007927/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007928/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007929 * fusion_init - Fusion MPT base driver initialization routine.
7930 *
7931 * Returns 0 for success, non-zero for failure.
7932 */
7933static int __init
7934fusion_init(void)
7935{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307936 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007937
7938 show_mptmod_ver(my_NAME, my_VERSION);
7939 printk(KERN_INFO COPYRIGHT "\n");
7940
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307941 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7942 MptCallbacks[cb_idx] = NULL;
7943 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7944 MptEvHandlers[cb_idx] = NULL;
7945 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007946 }
7947
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007948 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007949 * EventNotification handling.
7950 */
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05307951 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007952
7953 /* Register for hard reset handling callbacks.
7954 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307955 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007956
7957#ifdef CONFIG_PROC_FS
7958 (void) procmpt_create();
7959#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007960 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007961}
7962
7963/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007964/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007965 * fusion_exit - Perform driver unload cleanup.
7966 *
7967 * This routine frees all resources associated with each MPT adapter
7968 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7969 */
7970static void __exit
7971fusion_exit(void)
7972{
7973
Linus Torvalds1da177e2005-04-16 15:20:36 -07007974 mpt_reset_deregister(mpt_base_index);
7975
7976#ifdef CONFIG_PROC_FS
7977 procmpt_destroy();
7978#endif
7979}
7980
Linus Torvalds1da177e2005-04-16 15:20:36 -07007981module_init(fusion_init);
7982module_exit(fusion_exit);