blob: b88a244a1edd2e9754229a72b69801721acdfdc3 [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
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530118static char MptCallbacksName[MPT_MAX_PROTOCOL_DRIVERS][50];
Prakash, Sathya436ace72007-07-24 15:42:08 +0530119
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120#ifdef MFCNT
121static int mfcounter = 0;
122#define PRINT_MF_COUNT 20000
123#endif
124
125/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
126/*
127 * Public data...
128 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130#define WHOINIT_UNKNOWN 0xAA
131
132/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
133/*
134 * Private data...
135 */
136 /* Adapter link list */
137LIST_HEAD(ioc_list);
138 /* Callback lookup table */
139static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
140 /* Protocol driver class lookup table */
141static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
142 /* Event handler lookup table */
143static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
144 /* Reset handler lookup table */
145static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
146static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
147
Erik Ekmane47c11c2009-12-14 21:21:56 +0100148#ifdef CONFIG_PROC_FS
149static struct proc_dir_entry *mpt_proc_root_dir;
150#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530152/*
153 * Driver Callback Index's
154 */
155static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
156static u8 last_drv_idx;
157
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
159/*
160 * Forward protos...
161 */
David Howells7d12e782006-10-05 14:55:46 +0100162static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530163static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
164 MPT_FRAME_HDR *reply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
166 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
167 int sleepFlag);
168static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
169static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
170static void mpt_adapter_disable(MPT_ADAPTER *ioc);
171static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
172
173static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
174static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
176static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
177static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
178static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
179static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200180static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
182static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
183static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
184static int PrimeIocFifos(MPT_ADAPTER *ioc);
185static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
186static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
187static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
188static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200190int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
192static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
193static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
194static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530195static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Kashyap, Desaifd761752009-05-29 16:39:06 +0530196static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch,
197 int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200199static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
200static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
202#ifdef CONFIG_PROC_FS
203static int procmpt_summary_read(char *buf, char **start, off_t offset,
204 int request, int *eof, void *data);
205static int procmpt_version_read(char *buf, char **start, off_t offset,
206 int request, int *eof, void *data);
207static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
208 int request, int *eof, void *data);
209#endif
210static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
211
Kashyap, Desaifd761752009-05-29 16:39:06 +0530212static int ProcessEventNotification(MPT_ADAPTER *ioc,
213 EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700214static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700216static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530217static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info , u8 cb_idx);
Moore, Ericc972c702006-03-14 09:14:06 -0700218static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700219static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
221/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222static int __init fusion_init (void);
223static void __exit fusion_exit (void);
224
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225#define CHIPREG_READ32(addr) readl_relaxed(addr)
226#define CHIPREG_READ32_dmasync(addr) readl(addr)
227#define CHIPREG_WRITE32(addr,val) writel(val, addr)
228#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
229#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
230
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600231static void
232pci_disable_io_access(struct pci_dev *pdev)
233{
234 u16 command_reg;
235
236 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
237 command_reg &= ~1;
238 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
239}
240
241static void
242pci_enable_io_access(struct pci_dev *pdev)
243{
244 u16 command_reg;
245
246 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
247 command_reg |= 1;
248 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
249}
250
James Bottomleydb47c2d2007-07-28 13:40:21 -0400251static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
252{
253 int ret = param_set_int(val, kp);
254 MPT_ADAPTER *ioc;
255
256 if (ret)
257 return ret;
258
259 list_for_each_entry(ioc, &ioc_list, list)
260 ioc->debug_level = mpt_debug_level;
261 return 0;
262}
263
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530264/**
265 * mpt_get_cb_idx - obtain cb_idx for registered driver
266 * @dclass: class driver enum
267 *
268 * Returns cb_idx, or zero means it wasn't found
269 **/
270static u8
271mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
272{
273 u8 cb_idx;
274
275 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
276 if (MptDriverClass[cb_idx] == dclass)
277 return cb_idx;
278 return 0;
279}
280
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530281/**
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530282 * mpt_is_discovery_complete - determine if discovery has completed
283 * @ioc: per adatper instance
284 *
285 * Returns 1 when discovery completed, else zero.
286 */
287static int
288mpt_is_discovery_complete(MPT_ADAPTER *ioc)
289{
290 ConfigExtendedPageHeader_t hdr;
291 CONFIGPARMS cfg;
292 SasIOUnitPage0_t *buffer;
293 dma_addr_t dma_handle;
294 int rc = 0;
295
296 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
297 memset(&cfg, 0, sizeof(CONFIGPARMS));
298 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
299 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
300 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
301 cfg.cfghdr.ehdr = &hdr;
302 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
303
304 if ((mpt_config(ioc, &cfg)))
305 goto out;
306 if (!hdr.ExtPageLength)
307 goto out;
308
309 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
310 &dma_handle);
311 if (!buffer)
312 goto out;
313
314 cfg.physAddr = dma_handle;
315 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
316
317 if ((mpt_config(ioc, &cfg)))
318 goto out_free_consistent;
319
320 if (!(buffer->PhyData[0].PortFlags &
321 MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS))
322 rc = 1;
323
324 out_free_consistent:
325 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
326 buffer, dma_handle);
327 out:
328 return rc;
329}
330
331/**
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530332 * mpt_fault_reset_work - work performed on workq after ioc fault
333 * @work: input argument, used to derive ioc
334 *
335**/
336static void
337mpt_fault_reset_work(struct work_struct *work)
338{
339 MPT_ADAPTER *ioc =
340 container_of(work, MPT_ADAPTER, fault_reset_work.work);
341 u32 ioc_raw_state;
342 int rc;
343 unsigned long flags;
344
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530345 if (ioc->ioc_reset_in_progress || !ioc->active)
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530346 goto out;
347
348 ioc_raw_state = mpt_GetIocState(ioc, 0);
349 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
350 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700351 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530352 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700353 ioc->name, __func__);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530354 rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
355 printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700356 __func__, (rc == 0) ? "success" : "failed");
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530357 ioc_raw_state = mpt_GetIocState(ioc, 0);
358 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
359 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
360 "reset (%04xh)\n", ioc->name, ioc_raw_state &
361 MPI_DOORBELL_DATA_MASK);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530362 } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) {
363 if ((mpt_is_discovery_complete(ioc))) {
364 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing "
365 "discovery_quiesce_io flag\n", ioc->name));
366 ioc->sas_discovery_quiesce_io = 0;
367 }
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530368 }
369
370 out:
371 /*
372 * Take turns polling alternate controller
373 */
374 if (ioc->alt_ioc)
375 ioc = ioc->alt_ioc;
376
377 /* rearm the timer */
Kashyap, Desai2f187862009-05-29 16:52:37 +0530378 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530379 if (ioc->reset_work_q)
380 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
381 msecs_to_jiffies(MPT_POLLING_INTERVAL));
Kashyap, Desai2f187862009-05-29 16:52:37 +0530382 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530383}
384
385
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600386/*
387 * Process turbo (context) reply...
388 */
389static void
390mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
391{
392 MPT_FRAME_HDR *mf = NULL;
393 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530394 u16 req_idx = 0;
395 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600396
Prakash, Sathya436ace72007-07-24 15:42:08 +0530397 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600398 ioc->name, pa));
399
400 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
401 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
402 req_idx = pa & 0x0000FFFF;
403 cb_idx = (pa & 0x00FF0000) >> 16;
404 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
405 break;
406 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530407 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600408 /*
409 * Blind set of mf to NULL here was fatal
410 * after lan_reply says "freeme"
411 * Fix sort of combined with an optimization here;
412 * added explicit check for case where lan_reply
413 * was just returning 1 and doing nothing else.
414 * For this case skip the callback, but set up
415 * proper mf value first here:-)
416 */
417 if ((pa & 0x58000000) == 0x58000000) {
418 req_idx = pa & 0x0000FFFF;
419 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
420 mpt_free_msg_frame(ioc, mf);
421 mb();
422 return;
423 break;
424 }
425 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
426 break;
427 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530428 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600429 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
430 break;
431 default:
432 cb_idx = 0;
433 BUG();
434 }
435
436 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530437 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600438 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600439 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700440 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600441 goto out;
442 }
443
444 if (MptCallbacks[cb_idx](ioc, mf, mr))
445 mpt_free_msg_frame(ioc, mf);
446 out:
447 mb();
448}
449
450static void
451mpt_reply(MPT_ADAPTER *ioc, u32 pa)
452{
453 MPT_FRAME_HDR *mf;
454 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530455 u16 req_idx;
456 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600457 int freeme;
458
459 u32 reply_dma_low;
460 u16 ioc_stat;
461
462 /* non-TURBO reply! Hmmm, something may be up...
463 * Newest turbo reply mechanism; get address
464 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
465 */
466
467 /* Map DMA address of reply header to cpu address.
468 * pa is 32 bits - but the dma address may be 32 or 64 bits
469 * get offset based only only the low addresses
470 */
471
472 reply_dma_low = (pa <<= 1);
473 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
474 (reply_dma_low - ioc->reply_frames_low_dma));
475
476 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
477 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
478 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
479
Prakash, Sathya436ace72007-07-24 15:42:08 +0530480 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 -0600481 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600482 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600483
484 /* Check/log IOC log info
485 */
486 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
487 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
488 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
489 if (ioc->bus_type == FC)
490 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700491 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700492 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600493 else if (ioc->bus_type == SAS)
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530494 mpt_sas_log_info(ioc, log_info, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600495 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600496
Eric Moorec6c727a2007-01-29 09:44:54 -0700497 if (ioc_stat & MPI_IOCSTATUS_MASK)
498 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600499
500 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530501 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600502 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600503 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700504 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600505 freeme = 0;
506 goto out;
507 }
508
509 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
510
511 out:
512 /* Flush (non-TURBO) reply with a WRITE! */
513 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
514
515 if (freeme)
516 mpt_free_msg_frame(ioc, mf);
517 mb();
518}
519
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800521/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
523 * @irq: irq number (not used)
524 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 *
526 * This routine is registered via the request_irq() kernel API call,
527 * and handles all interrupts generated from a specific MPT adapter
528 * (also referred to as a IO Controller or IOC).
529 * This routine must clear the interrupt from the adapter and does
530 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200531 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 *
533 * This routine handles register-level access of the adapter but
534 * dispatches (calls) a protocol-specific callback routine to handle
535 * the protocol-specific details of the MPT request completion.
536 */
537static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100538mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600540 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600541 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
542
543 if (pa == 0xFFFFFFFF)
544 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
546 /*
547 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600549 do {
550 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600551 mpt_reply(ioc, pa);
552 else
553 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600554 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
555 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
557 return IRQ_HANDLED;
558}
559
560/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800561/**
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530562 * mptbase_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 * @ioc: Pointer to MPT_ADAPTER structure
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530564 * @req: Pointer to original MPT request frame
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
566 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800567 * MPT base driver's callback routine; all base driver
568 * "internal" request/reply processing is routed here.
569 * Currently used for EventNotification and EventAck handling.
570 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200571 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 * should be freed, or 0 if it shouldn't.
573 */
574static int
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530575mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530577 EventNotificationReply_t *pEventReply;
578 u8 event;
579 int evHandlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 int freereq = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530582 switch (reply->u.hdr.Function) {
583 case MPI_FUNCTION_EVENT_NOTIFICATION:
584 pEventReply = (EventNotificationReply_t *)reply;
585 evHandlers = 0;
586 ProcessEventNotification(ioc, pEventReply, &evHandlers);
587 event = le32_to_cpu(pEventReply->Event) & 0xFF;
588 if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 freereq = 0;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530590 if (event != MPI_EVENT_EVENT_CHANGE)
591 break;
592 case MPI_FUNCTION_CONFIG:
593 case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
594 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
595 if (reply) {
596 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
597 memcpy(ioc->mptbase_cmds.reply, reply,
598 min(MPT_DEFAULT_FRAME_SIZE,
599 4 * reply->u.reply.MsgLength));
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200600 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530601 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
602 ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
603 complete(&ioc->mptbase_cmds.done);
604 } else
605 freereq = 0;
606 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF)
607 freereq = 1;
608 break;
609 case MPI_FUNCTION_EVENT_ACK:
610 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
611 "EventAck reply received\n", ioc->name));
612 break;
613 default:
614 printk(MYIOC_s_ERR_FMT
615 "Unexpected msg function (=%02Xh) reply received!\n",
616 ioc->name, reply->u.hdr.Function);
617 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 }
619
620 /*
621 * Conditionally tell caller to free the original
622 * EventNotification/EventAck/unexpected request frame!
623 */
624 return freereq;
625}
626
627/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
628/**
629 * mpt_register - Register protocol-specific main callback handler.
630 * @cbfunc: callback function pointer
631 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
632 *
633 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800634 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 * protocol-specific driver must do this before it will be able to
636 * use any IOC resources, such as obtaining request frames.
637 *
638 * NOTES: The SCSI protocol driver currently calls this routine thrice
639 * in order to register separate callbacks; one for "normal" SCSI IO;
640 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
641 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530642 * Returns u8 valued "handle" in the range (and S.O.D. order)
643 * {N,...,7,6,5,...,1} if successful.
644 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
645 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530647u8
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530648mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass, char *func_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530650 u8 cb_idx;
651 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
653 /*
654 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
655 * (slot/handle 0 is reserved!)
656 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530657 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
658 if (MptCallbacks[cb_idx] == NULL) {
659 MptCallbacks[cb_idx] = cbfunc;
660 MptDriverClass[cb_idx] = dclass;
661 MptEvHandlers[cb_idx] = NULL;
662 last_drv_idx = cb_idx;
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530663 memcpy(MptCallbacksName[cb_idx], func_name,
664 strlen(func_name) > 50 ? 50 : strlen(func_name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 break;
666 }
667 }
668
669 return last_drv_idx;
670}
671
672/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
673/**
674 * mpt_deregister - Deregister a protocol drivers resources.
675 * @cb_idx: previously registered callback handle
676 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800677 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 * module is unloaded.
679 */
680void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530681mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600683 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 MptCallbacks[cb_idx] = NULL;
685 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
686 MptEvHandlers[cb_idx] = NULL;
687
688 last_drv_idx++;
689 }
690}
691
692/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
693/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800694 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 * @cb_idx: previously registered (via mpt_register) callback handle
696 * @ev_cbfunc: callback function
697 *
698 * This routine can be called by one or more protocol-specific drivers
699 * if/when they choose to be notified of MPT events.
700 *
701 * Returns 0 for success.
702 */
703int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530704mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600706 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 return -1;
708
709 MptEvHandlers[cb_idx] = ev_cbfunc;
710 return 0;
711}
712
713/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
714/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800715 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 * @cb_idx: previously registered callback handle
717 *
718 * Each protocol-specific driver should call this routine
719 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800720 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 */
722void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530723mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600725 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 return;
727
728 MptEvHandlers[cb_idx] = NULL;
729}
730
731/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
732/**
733 * mpt_reset_register - Register protocol-specific IOC reset handler.
734 * @cb_idx: previously registered (via mpt_register) callback handle
735 * @reset_func: reset function
736 *
737 * This routine can be called by one or more protocol-specific drivers
738 * if/when they choose to be notified of IOC resets.
739 *
740 * Returns 0 for success.
741 */
742int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530743mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530745 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 return -1;
747
748 MptResetHandlers[cb_idx] = reset_func;
749 return 0;
750}
751
752/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
753/**
754 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
755 * @cb_idx: previously registered callback handle
756 *
757 * Each protocol-specific driver should call this routine
758 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800759 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 */
761void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530762mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530764 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 return;
766
767 MptResetHandlers[cb_idx] = NULL;
768}
769
770/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
771/**
772 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800773 * @dd_cbfunc: driver callbacks struct
774 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 */
776int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530777mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778{
779 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600780 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
Eric Moore8d6d83e2007-09-14 18:47:40 -0600782 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400783 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
785 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
786
787 /* call per pci device probe entry point */
788 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600789 id = ioc->pcidev->driver ?
790 ioc->pcidev->driver->id_table : NULL;
791 if (dd_cbfunc->probe)
792 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 }
794
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400795 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796}
797
798/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
799/**
800 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800801 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 */
803void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530804mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805{
806 struct mpt_pci_driver *dd_cbfunc;
807 MPT_ADAPTER *ioc;
808
Eric Moore8d6d83e2007-09-14 18:47:40 -0600809 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 return;
811
812 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
813
814 list_for_each_entry(ioc, &ioc_list, list) {
815 if (dd_cbfunc->remove)
816 dd_cbfunc->remove(ioc->pcidev);
817 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200818
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 MptDeviceDriverHandlers[cb_idx] = NULL;
820}
821
822
823/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
824/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800825 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530826 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 * @ioc: Pointer to MPT adapter structure
828 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800829 * Obtain an MPT request frame from the pool (of 1024) that are
830 * allocated per MPT adapter.
831 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 * Returns pointer to a MPT request frame or %NULL if none are available
833 * or IOC is not active.
834 */
835MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530836mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837{
838 MPT_FRAME_HDR *mf;
839 unsigned long flags;
840 u16 req_idx; /* Request index */
841
842 /* validate handle and ioc identifier */
843
844#ifdef MFCNT
845 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600846 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
847 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848#endif
849
850 /* If interrupts are not attached, do not return a request frame */
851 if (!ioc->active)
852 return NULL;
853
854 spin_lock_irqsave(&ioc->FreeQlock, flags);
855 if (!list_empty(&ioc->FreeQ)) {
856 int req_offset;
857
858 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
859 u.frame.linkage.list);
860 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200861 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530862 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
864 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500865 req_idx = req_offset / ioc->req_sz;
866 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600868 /* Default, will be changed if necessary in SG generation */
869 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870#ifdef MFCNT
871 ioc->mfcnt++;
872#endif
873 }
874 else
875 mf = NULL;
876 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
877
878#ifdef MFCNT
879 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600880 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
881 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
882 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 mfcounter++;
884 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600885 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
886 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887#endif
888
Eric Moore29dd3602007-09-14 18:46:51 -0600889 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
890 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 return mf;
892}
893
894/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
895/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800896 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530897 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 * @ioc: Pointer to MPT adapter structure
899 * @mf: Pointer to MPT request frame
900 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800901 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 * specific MPT adapter.
903 */
904void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530905mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906{
907 u32 mf_dma_addr;
908 int req_offset;
909 u16 req_idx; /* Request index */
910
911 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530912 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
914 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500915 req_idx = req_offset / ioc->req_sz;
916 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
918
Prakash, Sathya436ace72007-07-24 15:42:08 +0530919 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200921 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600922 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
923 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
924 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
926}
927
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530928/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800929 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530930 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530931 * @ioc: Pointer to MPT adapter structure
932 * @mf: Pointer to MPT request frame
933 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800934 * Send a protocol-specific MPT request frame to an IOC using
935 * hi-priority request queue.
936 *
937 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530938 * specific MPT adapter.
939 **/
940void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530941mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530942{
943 u32 mf_dma_addr;
944 int req_offset;
945 u16 req_idx; /* Request index */
946
947 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530948 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530949 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
950 req_idx = req_offset / ioc->req_sz;
951 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
952 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
953
954 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
955
956 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
957 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
958 ioc->name, mf_dma_addr, req_idx));
959 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
960}
961
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
963/**
964 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 * @ioc: Pointer to MPT adapter structure
966 * @mf: Pointer to MPT request frame
967 *
968 * This routine places a MPT request frame back on the MPT adapter's
969 * FreeQ.
970 */
971void
972mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
973{
974 unsigned long flags;
975
976 /* Put Request back on FreeQ! */
977 spin_lock_irqsave(&ioc->FreeQlock, flags);
Kashyap, Desai2f187862009-05-29 16:52:37 +0530978 if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf)
979 goto out;
980 /* signature to know if this mf is freed */
981 mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
983#ifdef MFCNT
984 ioc->mfcnt--;
985#endif
Kashyap, Desai2f187862009-05-29 16:52:37 +0530986 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
988}
989
990/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
991/**
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530992 * mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 * @pAddr: virtual address for SGE
994 * @flagslength: SGE flags and data transfer length
995 * @dma_addr: Physical address
996 *
997 * This routine places a MPT request frame back on the MPT adapter's
998 * FreeQ.
999 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301000static void
1001mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002{
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301003 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
1004 pSge->FlagsLength = cpu_to_le32(flagslength);
1005 pSge->Address = cpu_to_le32(dma_addr);
1006}
1007
1008/**
1009 * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
1010 * @pAddr: virtual address for SGE
1011 * @flagslength: SGE flags and data transfer length
1012 * @dma_addr: Physical address
1013 *
1014 * This routine places a MPT request frame back on the MPT adapter's
1015 * FreeQ.
1016 **/
1017static void
1018mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1019{
1020 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1021 pSge->Address.Low = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301022 (lower_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301023 pSge->Address.High = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301024 (upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301025 pSge->FlagsLength = cpu_to_le32
1026 ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1027}
1028
1029/**
Randy Dunlap9cf46a32009-06-13 19:37:18 -07001030 * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr (1078 workaround).
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301031 * @pAddr: virtual address for SGE
1032 * @flagslength: SGE flags and data transfer length
1033 * @dma_addr: Physical address
1034 *
1035 * This routine places a MPT request frame back on the MPT adapter's
1036 * FreeQ.
1037 **/
1038static void
1039mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1040{
1041 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1042 u32 tmp;
1043
1044 pSge->Address.Low = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301045 (lower_32_bits(dma_addr));
1046 tmp = (u32)(upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301047
1048 /*
1049 * 1078 errata workaround for the 36GB limitation
1050 */
1051 if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {
1052 flagslength |=
1053 MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
1054 tmp |= (1<<31);
1055 if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
1056 printk(KERN_DEBUG "1078 P0M2 addressing for "
1057 "addr = 0x%llx len = %d\n",
1058 (unsigned long long)dma_addr,
1059 MPI_SGE_LENGTH(flagslength));
1060 }
1061
1062 pSge->Address.High = cpu_to_le32(tmp);
1063 pSge->FlagsLength = cpu_to_le32(
1064 (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1065}
1066
1067/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1068/**
1069 * mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
1070 * @pAddr: virtual address for SGE
1071 * @next: nextChainOffset value (u32's)
1072 * @length: length of next SGL segment
1073 * @dma_addr: Physical address
1074 *
1075 */
1076static void
1077mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1078{
1079 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
1080 pChain->Length = cpu_to_le16(length);
1081 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
1082 pChain->NextChainOffset = next;
1083 pChain->Address = cpu_to_le32(dma_addr);
1084}
1085
1086/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1087/**
1088 * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
1089 * @pAddr: virtual address for SGE
1090 * @next: nextChainOffset value (u32's)
1091 * @length: length of next SGL segment
1092 * @dma_addr: Physical address
1093 *
1094 */
1095static void
1096mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1097{
1098 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 u32 tmp = dma_addr & 0xFFFFFFFF;
1100
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301101 pChain->Length = cpu_to_le16(length);
1102 pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
1103 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301105 pChain->NextChainOffset = next;
1106
1107 pChain->Address.Low = cpu_to_le32(tmp);
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301108 tmp = (u32)(upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301109 pChain->Address.High = cpu_to_le32(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110}
1111
1112/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1113/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001114 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301115 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 * @ioc: Pointer to MPT adapter structure
1117 * @reqBytes: Size of the request in bytes
1118 * @req: Pointer to MPT request frame
1119 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1120 *
1121 * This routine is used exclusively to send MptScsiTaskMgmt
1122 * requests since they are required to be sent via doorbell handshake.
1123 *
1124 * NOTE: It is the callers responsibility to byte-swap fields in the
1125 * request which are greater than 1 byte in size.
1126 *
1127 * Returns 0 for success, non-zero for failure.
1128 */
1129int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301130mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131{
Eric Moorecd2c6192007-01-29 09:47:47 -07001132 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 u8 *req_as_bytes;
1134 int ii;
1135
1136 /* State is known to be good upon entering
1137 * this function so issue the bus reset
1138 * request.
1139 */
1140
1141 /*
1142 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1143 * setting cb_idx/req_idx. But ONLY if this request
1144 * is in proper (pre-alloc'd) request buffer range...
1145 */
1146 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1147 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1148 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1149 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301150 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 }
1152
1153 /* Make sure there are no doorbells */
1154 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001155
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1157 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1158 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1159
1160 /* Wait for IOC doorbell int */
1161 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1162 return ii;
1163 }
1164
1165 /* Read doorbell and check for active bit */
1166 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1167 return -5;
1168
Eric Moore29dd3602007-09-14 18:46:51 -06001169 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001170 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171
1172 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1173
1174 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1175 return -2;
1176 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001177
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 /* Send request via doorbell handshake */
1179 req_as_bytes = (u8 *) req;
1180 for (ii = 0; ii < reqBytes/4; ii++) {
1181 u32 word;
1182
1183 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1184 (req_as_bytes[(ii*4) + 1] << 8) |
1185 (req_as_bytes[(ii*4) + 2] << 16) |
1186 (req_as_bytes[(ii*4) + 3] << 24));
1187 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1188 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1189 r = -3;
1190 break;
1191 }
1192 }
1193
1194 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1195 r = 0;
1196 else
1197 r = -4;
1198
1199 /* Make sure there are no doorbells */
1200 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001201
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 return r;
1203}
1204
1205/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1206/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001207 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001208 * @ioc: Pointer to MPT adapter structure
1209 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001210 * @sleepFlag: Specifies whether the process can sleep
1211 *
1212 * Provides mechanism for the host driver to control the IOC's
1213 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001214 *
1215 * Access Control Value - bits[15:12]
1216 * 0h Reserved
1217 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1218 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1219 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1220 *
1221 * Returns 0 for success, non-zero for failure.
1222 */
1223
1224static int
1225mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1226{
1227 int r = 0;
1228
1229 /* return if in use */
1230 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1231 & MPI_DOORBELL_ACTIVE)
1232 return -1;
1233
1234 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1235
1236 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1237 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1238 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1239 (access_control_value<<12)));
1240
1241 /* Wait for IOC to clear Doorbell Status bit */
1242 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1243 return -2;
1244 }else
1245 return 0;
1246}
1247
1248/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1249/**
1250 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001251 * @ioc: Pointer to pointer to IOC adapter
1252 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001253 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001254 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001255 * Returns 0 for success, non-zero for failure.
1256 */
1257static int
1258mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1259{
1260 char *psge;
1261 int flags_length;
1262 u32 host_page_buffer_sz=0;
1263
1264 if(!ioc->HostPageBuffer) {
1265
1266 host_page_buffer_sz =
1267 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1268
1269 if(!host_page_buffer_sz)
1270 return 0; /* fw doesn't need any host buffers */
1271
1272 /* spin till we get enough memory */
1273 while(host_page_buffer_sz > 0) {
1274
1275 if((ioc->HostPageBuffer = pci_alloc_consistent(
1276 ioc->pcidev,
1277 host_page_buffer_sz,
1278 &ioc->HostPageBuffer_dma)) != NULL) {
1279
Prakash, Sathya436ace72007-07-24 15:42:08 +05301280 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001281 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001282 ioc->name, ioc->HostPageBuffer,
1283 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001284 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001285 ioc->alloc_total += host_page_buffer_sz;
1286 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1287 break;
1288 }
1289
1290 host_page_buffer_sz -= (4*1024);
1291 }
1292 }
1293
1294 if(!ioc->HostPageBuffer) {
1295 printk(MYIOC_s_ERR_FMT
1296 "Failed to alloc memory for host_page_buffer!\n",
1297 ioc->name);
1298 return -999;
1299 }
1300
1301 psge = (char *)&ioc_init->HostPageBufferSGE;
1302 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1303 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001304 MPI_SGE_FLAGS_HOST_TO_IOC |
1305 MPI_SGE_FLAGS_END_OF_BUFFER;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001306 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1307 flags_length |= ioc->HostPageBuffer_sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301308 ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001309 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1310
1311return 0;
1312}
1313
1314/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1315/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001316 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 * @iocid: IOC unique identifier (integer)
1318 * @iocpp: Pointer to pointer to IOC adapter
1319 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001320 * Given a unique IOC identifier, set pointer to the associated MPT
1321 * adapter structure.
1322 *
1323 * Returns iocid and sets iocpp if iocid is found.
1324 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 */
1326int
1327mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1328{
1329 MPT_ADAPTER *ioc;
1330
1331 list_for_each_entry(ioc,&ioc_list,list) {
1332 if (ioc->id == iocid) {
1333 *iocpp =ioc;
1334 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001337
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 *iocpp = NULL;
1339 return -1;
1340}
1341
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301342/**
1343 * mpt_get_product_name - returns product string
1344 * @vendor: pci vendor id
1345 * @device: pci device id
1346 * @revision: pci revision id
1347 * @prod_name: string returned
1348 *
1349 * Returns product string displayed when driver loads,
1350 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1351 *
1352 **/
1353static void
1354mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1355{
1356 char *product_str = NULL;
1357
1358 if (vendor == PCI_VENDOR_ID_BROCADE) {
1359 switch (device)
1360 {
1361 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1362 switch (revision)
1363 {
1364 case 0x00:
1365 product_str = "BRE040 A0";
1366 break;
1367 case 0x01:
1368 product_str = "BRE040 A1";
1369 break;
1370 default:
1371 product_str = "BRE040";
1372 break;
1373 }
1374 break;
1375 }
1376 goto out;
1377 }
1378
1379 switch (device)
1380 {
1381 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1382 product_str = "LSIFC909 B1";
1383 break;
1384 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1385 product_str = "LSIFC919 B0";
1386 break;
1387 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1388 product_str = "LSIFC929 B0";
1389 break;
1390 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1391 if (revision < 0x80)
1392 product_str = "LSIFC919X A0";
1393 else
1394 product_str = "LSIFC919XL A1";
1395 break;
1396 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1397 if (revision < 0x80)
1398 product_str = "LSIFC929X A0";
1399 else
1400 product_str = "LSIFC929XL A1";
1401 break;
1402 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1403 product_str = "LSIFC939X A1";
1404 break;
1405 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1406 product_str = "LSIFC949X A1";
1407 break;
1408 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1409 switch (revision)
1410 {
1411 case 0x00:
1412 product_str = "LSIFC949E A0";
1413 break;
1414 case 0x01:
1415 product_str = "LSIFC949E A1";
1416 break;
1417 default:
1418 product_str = "LSIFC949E";
1419 break;
1420 }
1421 break;
1422 case MPI_MANUFACTPAGE_DEVID_53C1030:
1423 switch (revision)
1424 {
1425 case 0x00:
1426 product_str = "LSI53C1030 A0";
1427 break;
1428 case 0x01:
1429 product_str = "LSI53C1030 B0";
1430 break;
1431 case 0x03:
1432 product_str = "LSI53C1030 B1";
1433 break;
1434 case 0x07:
1435 product_str = "LSI53C1030 B2";
1436 break;
1437 case 0x08:
1438 product_str = "LSI53C1030 C0";
1439 break;
1440 case 0x80:
1441 product_str = "LSI53C1030T A0";
1442 break;
1443 case 0x83:
1444 product_str = "LSI53C1030T A2";
1445 break;
1446 case 0x87:
1447 product_str = "LSI53C1030T A3";
1448 break;
1449 case 0xc1:
1450 product_str = "LSI53C1020A A1";
1451 break;
1452 default:
1453 product_str = "LSI53C1030";
1454 break;
1455 }
1456 break;
1457 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1458 switch (revision)
1459 {
1460 case 0x03:
1461 product_str = "LSI53C1035 A2";
1462 break;
1463 case 0x04:
1464 product_str = "LSI53C1035 B0";
1465 break;
1466 default:
1467 product_str = "LSI53C1035";
1468 break;
1469 }
1470 break;
1471 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1472 switch (revision)
1473 {
1474 case 0x00:
1475 product_str = "LSISAS1064 A1";
1476 break;
1477 case 0x01:
1478 product_str = "LSISAS1064 A2";
1479 break;
1480 case 0x02:
1481 product_str = "LSISAS1064 A3";
1482 break;
1483 case 0x03:
1484 product_str = "LSISAS1064 A4";
1485 break;
1486 default:
1487 product_str = "LSISAS1064";
1488 break;
1489 }
1490 break;
1491 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1492 switch (revision)
1493 {
1494 case 0x00:
1495 product_str = "LSISAS1064E A0";
1496 break;
1497 case 0x01:
1498 product_str = "LSISAS1064E B0";
1499 break;
1500 case 0x02:
1501 product_str = "LSISAS1064E B1";
1502 break;
1503 case 0x04:
1504 product_str = "LSISAS1064E B2";
1505 break;
1506 case 0x08:
1507 product_str = "LSISAS1064E B3";
1508 break;
1509 default:
1510 product_str = "LSISAS1064E";
1511 break;
1512 }
1513 break;
1514 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1515 switch (revision)
1516 {
1517 case 0x00:
1518 product_str = "LSISAS1068 A0";
1519 break;
1520 case 0x01:
1521 product_str = "LSISAS1068 B0";
1522 break;
1523 case 0x02:
1524 product_str = "LSISAS1068 B1";
1525 break;
1526 default:
1527 product_str = "LSISAS1068";
1528 break;
1529 }
1530 break;
1531 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1532 switch (revision)
1533 {
1534 case 0x00:
1535 product_str = "LSISAS1068E A0";
1536 break;
1537 case 0x01:
1538 product_str = "LSISAS1068E B0";
1539 break;
1540 case 0x02:
1541 product_str = "LSISAS1068E B1";
1542 break;
1543 case 0x04:
1544 product_str = "LSISAS1068E B2";
1545 break;
1546 case 0x08:
1547 product_str = "LSISAS1068E B3";
1548 break;
1549 default:
1550 product_str = "LSISAS1068E";
1551 break;
1552 }
1553 break;
1554 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1555 switch (revision)
1556 {
1557 case 0x00:
1558 product_str = "LSISAS1078 A0";
1559 break;
1560 case 0x01:
1561 product_str = "LSISAS1078 B0";
1562 break;
1563 case 0x02:
1564 product_str = "LSISAS1078 C0";
1565 break;
1566 case 0x03:
1567 product_str = "LSISAS1078 C1";
1568 break;
1569 case 0x04:
1570 product_str = "LSISAS1078 C2";
1571 break;
1572 default:
1573 product_str = "LSISAS1078";
1574 break;
1575 }
1576 break;
1577 }
1578
1579 out:
1580 if (product_str)
1581 sprintf(prod_name, "%s", product_str);
1582}
1583
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301584/**
1585 * mpt_mapresources - map in memory mapped io
1586 * @ioc: Pointer to pointer to IOC adapter
1587 *
1588 **/
1589static int
1590mpt_mapresources(MPT_ADAPTER *ioc)
1591{
1592 u8 __iomem *mem;
1593 int ii;
Pravin Bathijae46b63b2009-12-02 17:51:46 -08001594 resource_size_t mem_phys;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301595 unsigned long port;
1596 u32 msize;
1597 u32 psize;
1598 u8 revision;
1599 int r = -ENODEV;
1600 struct pci_dev *pdev;
1601
1602 pdev = ioc->pcidev;
1603 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1604 if (pci_enable_device_mem(pdev)) {
1605 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1606 "failed\n", ioc->name);
1607 return r;
1608 }
1609 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1610 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1611 "MEM failed\n", ioc->name);
1612 return r;
1613 }
1614
1615 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1616
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301617 if (sizeof(dma_addr_t) > 4) {
1618 const uint64_t required_mask = dma_get_required_mask
1619 (&pdev->dev);
1620 if (required_mask > DMA_BIT_MASK(32)
1621 && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
1622 && !pci_set_consistent_dma_mask(pdev,
1623 DMA_BIT_MASK(64))) {
1624 ioc->dma_mask = DMA_BIT_MASK(64);
1625 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1626 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1627 ioc->name));
1628 } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1629 && !pci_set_consistent_dma_mask(pdev,
1630 DMA_BIT_MASK(32))) {
1631 ioc->dma_mask = DMA_BIT_MASK(32);
1632 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1633 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1634 ioc->name));
1635 } else {
1636 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1637 ioc->name, pci_name(pdev));
Tomas Henzl653c42d2010-07-26 16:41:13 +02001638 pci_release_selected_regions(pdev, ioc->bars);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301639 return r;
1640 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301641 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301642 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1643 && !pci_set_consistent_dma_mask(pdev,
1644 DMA_BIT_MASK(32))) {
1645 ioc->dma_mask = DMA_BIT_MASK(32);
1646 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1647 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1648 ioc->name));
1649 } else {
1650 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1651 ioc->name, pci_name(pdev));
Tomas Henzl653c42d2010-07-26 16:41:13 +02001652 pci_release_selected_regions(pdev, ioc->bars);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301653 return r;
1654 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301655 }
1656
1657 mem_phys = msize = 0;
1658 port = psize = 0;
1659 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1660 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1661 if (psize)
1662 continue;
1663 /* Get I/O space! */
1664 port = pci_resource_start(pdev, ii);
1665 psize = pci_resource_len(pdev, ii);
1666 } else {
1667 if (msize)
1668 continue;
1669 /* Get memmap */
1670 mem_phys = pci_resource_start(pdev, ii);
1671 msize = pci_resource_len(pdev, ii);
1672 }
1673 }
1674 ioc->mem_size = msize;
1675
1676 mem = NULL;
1677 /* Get logical ptr for PciMem0 space */
1678 /*mem = ioremap(mem_phys, msize);*/
1679 mem = ioremap(mem_phys, msize);
1680 if (mem == NULL) {
1681 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1682 " memory!\n", ioc->name);
Tomas Henzl653c42d2010-07-26 16:41:13 +02001683 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301684 return -EINVAL;
1685 }
1686 ioc->memmap = mem;
Pravin Bathijae46b63b2009-12-02 17:51:46 -08001687 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %llx\n",
1688 ioc->name, mem, (unsigned long long)mem_phys));
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301689
1690 ioc->mem_phys = mem_phys;
1691 ioc->chip = (SYSIF_REGS __iomem *)mem;
1692
1693 /* Save Port IO values in case we need to do downloadboot */
1694 ioc->pio_mem_phys = port;
1695 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1696
1697 return 0;
1698}
1699
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001701/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001702 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001704 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 *
1706 * This routine performs all the steps necessary to bring the IOC of
1707 * a MPT adapter to a OPERATIONAL state. This includes registering
1708 * memory regions, registering the interrupt, and allocating request
1709 * and reply memory pools.
1710 *
1711 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1712 * MPT adapter.
1713 *
1714 * Returns 0 for success, non-zero for failure.
1715 *
1716 * TODO: Add support for polled controllers
1717 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001718int
1719mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720{
1721 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301722 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 u8 revision;
1725 u8 pcixcmd;
1726 static int mpt_ids = 0;
1727#ifdef CONFIG_PROC_FS
1728 struct proc_dir_entry *dent, *ent;
1729#endif
1730
Jesper Juhl56876192007-08-10 14:50:51 -07001731 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1732 if (ioc == NULL) {
1733 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1734 return -ENOMEM;
1735 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301736
Eric Moore29dd3602007-09-14 18:46:51 -06001737 ioc->id = mpt_ids++;
1738 sprintf(ioc->name, "ioc%d", ioc->id);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301739 dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Jesper Juhl56876192007-08-10 14:50:51 -07001740
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301741 /*
1742 * set initial debug level
1743 * (refer to mptdebug.h)
1744 *
1745 */
1746 ioc->debug_level = mpt_debug_level;
1747 if (mpt_debug_level)
1748 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301749
Eric Moore29dd3602007-09-14 18:46:51 -06001750 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001751
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301752 ioc->pcidev = pdev;
1753 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001754 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 return r;
1756 }
1757
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301758 /*
1759 * Setting up proper handlers for scatter gather handling
1760 */
1761 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
1762 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
1763 ioc->add_sge = &mpt_add_sge_64bit_1078;
1764 else
1765 ioc->add_sge = &mpt_add_sge_64bit;
1766 ioc->add_chain = &mpt_add_chain_64bit;
1767 ioc->sg_addr_size = 8;
1768 } else {
1769 ioc->add_sge = &mpt_add_sge;
1770 ioc->add_chain = &mpt_add_chain;
1771 ioc->sg_addr_size = 4;
1772 }
1773 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
1774
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 ioc->alloc_total = sizeof(MPT_ADAPTER);
1776 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1777 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001778
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301780 spin_lock_init(&ioc->taskmgmt_lock);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05301781 mutex_init(&ioc->internal_cmds.mutex);
1782 init_completion(&ioc->internal_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301783 mutex_init(&ioc->mptbase_cmds.mutex);
1784 init_completion(&ioc->mptbase_cmds.done);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301785 mutex_init(&ioc->taskmgmt_cmds.mutex);
1786 init_completion(&ioc->taskmgmt_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301787
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 /* Initialize the event logging.
1789 */
1790 ioc->eventTypes = 0; /* None */
1791 ioc->eventContext = 0;
1792 ioc->eventLogSize = 0;
1793 ioc->events = NULL;
1794
1795#ifdef MFCNT
1796 ioc->mfcnt = 0;
1797#endif
1798
Kashyap, Desai2f187862009-05-29 16:52:37 +05301799 ioc->sh = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 ioc->cached_fw = NULL;
1801
Uwe Kleine-König421f91d2010-06-11 12:17:00 +02001802 /* Initialize SCSI Config Data structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001804 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805
Michael Reed05e8ec12006-01-13 14:31:54 -06001806 /* Initialize the fc rport list head.
1807 */
1808 INIT_LIST_HEAD(&ioc->fc_rports);
1809
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 /* Find lookup slot. */
1811 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001812
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301813
1814 /* Initialize workqueue */
1815 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301816
Kashyap, Desai2f187862009-05-29 16:52:37 +05301817 snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN,
Kay Sieversaab0de22008-05-02 06:02:41 +02001818 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301819 ioc->reset_work_q =
1820 create_singlethread_workqueue(ioc->reset_work_q_name);
1821 if (!ioc->reset_work_q) {
1822 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1823 ioc->name);
1824 pci_release_selected_regions(pdev, ioc->bars);
1825 kfree(ioc);
1826 return -ENOMEM;
1827 }
1828
Eric Moore29dd3602007-09-14 18:46:51 -06001829 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1830 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301832 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1833 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1834
1835 switch (pdev->device)
1836 {
1837 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1838 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1839 ioc->errata_flag_1064 = 1;
1840 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1841 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1842 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1843 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301845 break;
1846
1847 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 /* 929X Chip Fix. Set Split transactions level
1850 * for PCIX. Set MOST bits to zero.
1851 */
1852 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1853 pcixcmd &= 0x8F;
1854 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1855 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 /* 929XL Chip Fix. Set MMRBC to 0x08.
1857 */
1858 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1859 pcixcmd |= 0x08;
1860 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1861 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301863 break;
1864
1865 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 /* 919X Chip Fix. Set Split transactions level
1867 * for PCIX. Set MOST bits to zero.
1868 */
1869 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1870 pcixcmd &= 0x8F;
1871 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001872 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301873 break;
1874
1875 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 /* 1030 Chip Fix. Disable Split transactions
1877 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1878 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 if (revision < C0_1030) {
1880 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1881 pcixcmd &= 0x8F;
1882 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1883 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301884
1885 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001886 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301887 break;
1888
1889 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1890 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001891 ioc->errata_flag_1064 = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301892 ioc->bus_type = SAS;
1893 break;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301894
1895 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1896 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1897 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001898 ioc->bus_type = SAS;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301899 break;
Eric Moore87cf8982006-06-27 16:09:26 -06001900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301902
Kashyap, Desaie3829682009-01-08 14:27:16 +05301903 switch (ioc->bus_type) {
1904
1905 case SAS:
1906 ioc->msi_enable = mpt_msi_enable_sas;
1907 break;
1908
1909 case SPI:
1910 ioc->msi_enable = mpt_msi_enable_spi;
1911 break;
1912
1913 case FC:
1914 ioc->msi_enable = mpt_msi_enable_fc;
1915 break;
1916
1917 default:
1918 ioc->msi_enable = 0;
1919 break;
1920 }
Kashyap, Desai8ce13de2010-06-17 14:35:46 +05301921
1922 ioc->fw_events_off = 1;
1923
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001924 if (ioc->errata_flag_1064)
1925 pci_disable_io_access(pdev);
1926
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 spin_lock_init(&ioc->FreeQlock);
1928
1929 /* Disable all! */
1930 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1931 ioc->active = 0;
1932 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1933
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301934 /* Set IOC ptr in the pcidev's driver data. */
1935 pci_set_drvdata(ioc->pcidev, ioc);
1936
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 /* Set lookup ptr. */
1938 list_add_tail(&ioc->list, &ioc_list);
1939
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001940 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 */
1942 mpt_detect_bound_ports(ioc, pdev);
1943
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301944 INIT_LIST_HEAD(&ioc->fw_event_list);
1945 spin_lock_init(&ioc->fw_event_lock);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301946 snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301947 ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
1948
James Bottomleyc92f2222006-03-01 09:02:49 -06001949 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1950 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001951 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1952 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001953
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001955 if (ioc->alt_ioc)
1956 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301957 iounmap(ioc->memmap);
1958 if (r != -5)
1959 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301960
1961 destroy_workqueue(ioc->reset_work_q);
1962 ioc->reset_work_q = NULL;
1963
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 kfree(ioc);
1965 pci_set_drvdata(pdev, NULL);
1966 return r;
1967 }
1968
1969 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001970 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301971 if(MptDeviceDriverHandlers[cb_idx] &&
1972 MptDeviceDriverHandlers[cb_idx]->probe) {
1973 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 }
1975 }
1976
1977#ifdef CONFIG_PROC_FS
1978 /*
1979 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1980 */
1981 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1982 if (dent) {
1983 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1984 if (ent) {
1985 ent->read_proc = procmpt_iocinfo_read;
1986 ent->data = ioc;
1987 }
1988 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1989 if (ent) {
1990 ent->read_proc = procmpt_summary_read;
1991 ent->data = ioc;
1992 }
1993 }
1994#endif
1995
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301996 if (!ioc->alt_ioc)
1997 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1998 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1999
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 return 0;
2001}
2002
2003/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002004/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002005 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 */
2008
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002009void
2010mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011{
2012 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2013 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302014 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302015 unsigned long flags;
2016 struct workqueue_struct *wq;
2017
2018 /*
2019 * Stop polling ioc for fault condition
2020 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302021 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302022 wq = ioc->reset_work_q;
2023 ioc->reset_work_q = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302024 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302025 cancel_delayed_work(&ioc->fault_reset_work);
2026 destroy_workqueue(wq);
2027
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05302028 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2029 wq = ioc->fw_event_q;
2030 ioc->fw_event_q = NULL;
2031 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2032 destroy_workqueue(wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033
2034 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2035 remove_proc_entry(pname, NULL);
2036 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2037 remove_proc_entry(pname, NULL);
2038 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2039 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002040
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002042 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302043 if(MptDeviceDriverHandlers[cb_idx] &&
2044 MptDeviceDriverHandlers[cb_idx]->remove) {
2045 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 }
2047 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002048
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 /* Disable interrupts! */
2050 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2051
2052 ioc->active = 0;
2053 synchronize_irq(pdev->irq);
2054
2055 /* Clear any lingering interrupt */
2056 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2057
2058 CHIPREG_READ32(&ioc->chip->IntStatus);
2059
2060 mpt_adapter_dispose(ioc);
2061
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062}
2063
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064/**************************************************************************
2065 * Power Management
2066 */
2067#ifdef CONFIG_PM
2068/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002069/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002070 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002071 * @pdev: Pointer to pci_dev structure
2072 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002074int
2075mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076{
2077 u32 device_state;
2078 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302080 device_state = pci_choose_state(pdev, state);
2081 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2082 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2083 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084
2085 /* put ioc into READY_STATE */
2086 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2087 printk(MYIOC_s_ERR_FMT
2088 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2089 }
2090
2091 /* disable interrupts */
2092 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2093 ioc->active = 0;
2094
2095 /* Clear any lingering interrupt */
2096 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2097
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302098 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002099 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302100 pci_disable_msi(ioc->pcidev);
2101 ioc->pci_irq = -1;
2102 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302104 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 return 0;
2107}
2108
2109/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002110/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002111 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002112 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002114int
2115mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116{
2117 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2118 u32 device_state = pdev->current_state;
2119 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302120 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002121
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302122 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2123 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2124 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302126 pci_set_power_state(pdev, PCI_D0);
2127 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302129 ioc->pcidev = pdev;
2130 err = mpt_mapresources(ioc);
2131 if (err)
2132 return err;
2133
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302134 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2135 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2136 ioc->add_sge = &mpt_add_sge_64bit_1078;
2137 else
2138 ioc->add_sge = &mpt_add_sge_64bit;
2139 ioc->add_chain = &mpt_add_chain_64bit;
2140 ioc->sg_addr_size = 8;
2141 } else {
2142
2143 ioc->add_sge = &mpt_add_sge;
2144 ioc->add_chain = &mpt_add_chain;
2145 ioc->sg_addr_size = 4;
2146 }
2147 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2148
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302149 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2150 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2151 CHIPREG_READ32(&ioc->chip->Doorbell));
2152
2153 /*
2154 * Errata workaround for SAS pci express:
2155 * Upon returning to the D0 state, the contents of the doorbell will be
2156 * stale data, and this will incorrectly signal to the host driver that
2157 * the firmware is ready to process mpt commands. The workaround is
2158 * to issue a diagnostic reset.
2159 */
2160 if (ioc->bus_type == SAS && (pdev->device ==
2161 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2162 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2163 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2164 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2165 ioc->name);
2166 goto out;
2167 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302168 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169
2170 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302171 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2172 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2173 CAN_SLEEP);
2174 if (recovery_state != 0)
2175 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2176 "error:[%x]\n", ioc->name, recovery_state);
2177 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302179 "pci-resume: success\n", ioc->name);
2180 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302182
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183}
2184#endif
2185
James Bottomley4ff42a62006-05-17 18:06:52 -05002186static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302187mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002188{
2189 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2190 ioc->bus_type != SPI) ||
2191 (MptDriverClass[index] == MPTFC_DRIVER &&
2192 ioc->bus_type != FC) ||
2193 (MptDriverClass[index] == MPTSAS_DRIVER &&
2194 ioc->bus_type != SAS))
2195 /* make sure we only call the relevant reset handler
2196 * for the bus */
2197 return 0;
2198 return (MptResetHandlers[index])(ioc, reset_phase);
2199}
2200
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002202/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2204 * @ioc: Pointer to MPT adapter structure
2205 * @reason: Event word / reason
2206 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2207 *
2208 * This routine performs all the steps necessary to bring the IOC
2209 * to a OPERATIONAL state.
2210 *
2211 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2212 * MPT adapter.
2213 *
2214 * Returns:
2215 * 0 for success
2216 * -1 if failed to get board READY
2217 * -2 if READY but IOCFacts Failed
2218 * -3 if READY but PrimeIOCFifos Failed
2219 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302220 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302221 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 */
2223static int
2224mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2225{
2226 int hard_reset_done = 0;
2227 int alt_ioc_ready = 0;
2228 int hard;
2229 int rc=0;
2230 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 int ret = 0;
2232 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002233 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302234 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235
Eric Moore29dd3602007-09-14 18:46:51 -06002236 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2237 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238
2239 /* Disable reply interrupts (also blocks FreeQ) */
2240 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2241 ioc->active = 0;
2242
2243 if (ioc->alt_ioc) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302244 if (ioc->alt_ioc->active ||
2245 reason == MPT_HOSTEVENT_IOC_RECOVER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 reset_alt_ioc_active = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302247 /* Disable alt-IOC's reply interrupts
2248 * (and FreeQ) for a bit
2249 **/
2250 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2251 0xFFFFFFFF);
2252 ioc->alt_ioc->active = 0;
2253 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 }
2255
2256 hard = 1;
2257 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2258 hard = 0;
2259
2260 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2261 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002262 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2263 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264
2265 if (reset_alt_ioc_active && ioc->alt_ioc) {
2266 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002267 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2268 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002269 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 ioc->alt_ioc->active = 1;
2271 }
2272
2273 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302274 printk(MYIOC_s_WARN_FMT
2275 "NOT READY WARNING!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302277 ret = -1;
2278 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 }
2280
2281 /* hard_reset_done = 0 if a soft reset was performed
2282 * and 1 if a hard reset was performed.
2283 */
2284 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2285 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2286 alt_ioc_ready = 1;
2287 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05302288 printk(MYIOC_s_WARN_FMT
2289 ": alt-ioc Not ready WARNING!\n",
2290 ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 }
2292
2293 for (ii=0; ii<5; ii++) {
2294 /* Get IOC facts! Allow 5 retries */
2295 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2296 break;
2297 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002298
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299
2300 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002301 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2302 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 ret = -2;
2304 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2305 MptDisplayIocCapabilities(ioc);
2306 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002307
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 if (alt_ioc_ready) {
2309 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302310 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302311 "Initial Alt IocFacts failed rc=%x\n",
2312 ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 /* Retry - alt IOC was initialized once
2314 */
2315 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2316 }
2317 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302318 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002319 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 alt_ioc_ready = 0;
2321 reset_alt_ioc_active = 0;
2322 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2323 MptDisplayIocCapabilities(ioc->alt_ioc);
2324 }
2325 }
2326
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302327 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2328 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2329 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2330 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2331 IORESOURCE_IO);
2332 if (pci_enable_device(ioc->pcidev))
2333 return -5;
2334 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2335 "mpt"))
2336 return -5;
2337 }
2338
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002339 /*
2340 * Device is reset now. It must have de-asserted the interrupt line
2341 * (if it was asserted) and it should be safe to register for the
2342 * interrupt now.
2343 */
2344 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2345 ioc->pci_irq = -1;
2346 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302347 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002348 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002349 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302350 else
2351 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002352 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002353 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002354 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002355 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Kashyap, Desai2f187862009-05-29 16:52:37 +05302356 "interrupt %d!\n",
2357 ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302358 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002359 pci_disable_msi(ioc->pcidev);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302360 ret = -EBUSY;
2361 goto out;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002362 }
2363 irq_allocated = 1;
2364 ioc->pci_irq = ioc->pcidev->irq;
2365 pci_set_master(ioc->pcidev); /* ?? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302366 pci_set_drvdata(ioc->pcidev, ioc);
2367 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2368 "installed at interrupt %d\n", ioc->name,
2369 ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002370 }
2371 }
2372
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 /* Prime reply & request queues!
2374 * (mucho alloc's) Must be done prior to
2375 * init as upper addresses are needed for init.
2376 * If fails, continue with alt-ioc processing
2377 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302378 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
2379 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2381 ret = -3;
2382
2383 /* May need to check/upload firmware & data here!
2384 * If fails, continue with alt-ioc processing
2385 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302386 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
2387 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2389 ret = -4;
2390// NEW!
2391 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302392 printk(MYIOC_s_WARN_FMT
2393 ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002394 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 alt_ioc_ready = 0;
2396 reset_alt_ioc_active = 0;
2397 }
2398
2399 if (alt_ioc_ready) {
2400 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2401 alt_ioc_ready = 0;
2402 reset_alt_ioc_active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302403 printk(MYIOC_s_WARN_FMT
2404 ": alt-ioc: (%d) init failure WARNING!\n",
2405 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 }
2407 }
2408
2409 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2410 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302411 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002412 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413
2414 /* Controller is not operational, cannot do upload
2415 */
2416 if (ret == 0) {
2417 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002418 if (rc == 0) {
2419 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2420 /*
2421 * Maintain only one pointer to FW memory
2422 * so there will not be two attempt to
2423 * downloadboot onboard dual function
2424 * chips (mpt_adapter_disable,
2425 * mpt_diag_reset)
2426 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302427 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002428 "mpt_upload: alt_%s has cached_fw=%p \n",
2429 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302430 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002431 }
2432 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002433 printk(MYIOC_s_WARN_FMT
2434 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302435 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002436 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 }
2438 }
2439 }
2440
Kashyap, Desaifd761752009-05-29 16:39:06 +05302441 /* Enable MPT base driver management of EventNotification
2442 * and EventAck handling.
2443 */
2444 if ((ret == 0) && (!ioc->facts.EventState)) {
2445 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2446 "SendEventNotification\n",
2447 ioc->name));
2448 ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
2449 }
2450
2451 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2452 rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
2453
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 if (ret == 0) {
2455 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002456 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 ioc->active = 1;
2458 }
Kashyap, Desaifd761752009-05-29 16:39:06 +05302459 if (rc == 0) { /* alt ioc */
2460 if (reset_alt_ioc_active && ioc->alt_ioc) {
2461 /* (re)Enable alt-IOC! (reply interrupt) */
2462 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
2463 "reply irq re-enabled\n",
2464 ioc->alt_ioc->name));
2465 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2466 MPI_HIM_DIM);
2467 ioc->alt_ioc->active = 1;
2468 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 }
2470
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002472 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2474 * recursive scenario; GetLanConfigPages times out, timer expired
2475 * routine calls HardResetHandler, which calls into here again,
2476 * and we try GetLanConfigPages again...
2477 */
2478 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002479
2480 /*
Uwe Kleine-König421f91d2010-06-11 12:17:00 +02002481 * Initialize link list for inactive raid volumes.
Eric Mooreb506ade2007-01-29 09:45:37 -07002482 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002483 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002484 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2485
Kashyap, Desai2f187862009-05-29 16:52:37 +05302486 switch (ioc->bus_type) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002487
Kashyap, Desai2f187862009-05-29 16:52:37 +05302488 case SAS:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002489 /* clear persistency table */
2490 if(ioc->facts.IOCExceptions &
2491 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2492 ret = mptbase_sas_persist_operation(ioc,
2493 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2494 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002495 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002496 }
2497
2498 /* Find IM volumes
2499 */
2500 mpt_findImVolumes(ioc);
2501
Kashyap, Desai2f187862009-05-29 16:52:37 +05302502 /* Check, and possibly reset, the coalescing value
2503 */
2504 mpt_read_ioc_pg_1(ioc);
2505
2506 break;
2507
2508 case FC:
2509 if ((ioc->pfacts[0].ProtocolFlags &
2510 MPI_PORTFACTS_PROTOCOL_LAN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2512 /*
2513 * Pre-fetch the ports LAN MAC address!
2514 * (LANPage1_t stuff)
2515 */
2516 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302517 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2518 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302519 "LanAddr = %02X:%02X:%02X"
2520 ":%02X:%02X:%02X\n",
2521 ioc->name, a[5], a[4],
2522 a[3], a[2], a[1], a[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302524 break;
2525
2526 case SPI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 /* Get NVRAM and adapter maximums from SPP 0 and 2
2528 */
2529 mpt_GetScsiPortSettings(ioc, 0);
2530
2531 /* Get version and length of SDP 1
2532 */
2533 mpt_readScsiDevicePageHeaders(ioc, 0);
2534
2535 /* Find IM volumes
2536 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002537 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 mpt_findImVolumes(ioc);
2539
2540 /* Check, and possibly reset, the coalescing value
2541 */
2542 mpt_read_ioc_pg_1(ioc);
2543
2544 mpt_read_ioc_pg_4(ioc);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302545
2546 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 }
2548
2549 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302550 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 }
2552
Eric Moore0ccdb002006-07-11 17:33:13 -06002553 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002554 if ((ret != 0) && irq_allocated) {
2555 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302556 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002557 pci_disable_msi(ioc->pcidev);
2558 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 return ret;
2560}
2561
2562/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002563/**
2564 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 * @ioc: Pointer to MPT adapter structure
2566 * @pdev: Pointer to (struct pci_dev) structure
2567 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002568 * Search for PCI bus/dev_function which matches
2569 * PCI bus/dev_function (+/-1) for newly discovered 929,
2570 * 929X, 1030 or 1035.
2571 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2573 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2574 */
2575static void
2576mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2577{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002578 struct pci_dev *peer=NULL;
2579 unsigned int slot = PCI_SLOT(pdev->devfn);
2580 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 MPT_ADAPTER *ioc_srch;
2582
Prakash, Sathya436ace72007-07-24 15:42:08 +05302583 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002584 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002585 ioc->name, pci_name(pdev), pdev->bus->number,
2586 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002587
2588 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2589 if (!peer) {
2590 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2591 if (!peer)
2592 return;
2593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594
2595 list_for_each_entry(ioc_srch, &ioc_list, list) {
2596 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002597 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 /* Paranoia checks */
2599 if (ioc->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302600 printk(MYIOC_s_WARN_FMT
2601 "Oops, already bound (%s <==> %s)!\n",
2602 ioc->name, ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 break;
2604 } else if (ioc_srch->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302605 printk(MYIOC_s_WARN_FMT
2606 "Oops, already bound (%s <==> %s)!\n",
2607 ioc_srch->name, ioc_srch->name,
2608 ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 break;
2610 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302611 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2612 "FOUND! binding %s <==> %s\n",
2613 ioc->name, ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 ioc_srch->alt_ioc = ioc;
2615 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 }
2617 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002618 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619}
2620
2621/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002622/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002624 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 */
2626static void
2627mpt_adapter_disable(MPT_ADAPTER *ioc)
2628{
2629 int sz;
2630 int ret;
2631
2632 if (ioc->cached_fw != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302633 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2634 "%s: Pushing FW onto adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302635 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2636 ioc->cached_fw, CAN_SLEEP)) < 0) {
2637 printk(MYIOC_s_WARN_FMT
2638 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002639 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 }
2641 }
2642
Kashyap, Desai71278192009-05-29 16:53:14 +05302643 /*
2644 * Put the controller into ready state (if its not already)
2645 */
2646 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {
2647 if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
2648 CAN_SLEEP)) {
2649 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)
2650 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit "
2651 "reset failed to put ioc in ready state!\n",
2652 ioc->name, __func__);
2653 } else
2654 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset "
2655 "failed!\n", ioc->name, __func__);
2656 }
2657
2658
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 /* Disable adapter interrupts! */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302660 synchronize_irq(ioc->pcidev->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2662 ioc->active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302663
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 /* Clear any lingering interrupt */
2665 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302666 CHIPREG_READ32(&ioc->chip->IntStatus);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667
2668 if (ioc->alloc != NULL) {
2669 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002670 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2671 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 pci_free_consistent(ioc->pcidev, sz,
2673 ioc->alloc, ioc->alloc_dma);
2674 ioc->reply_frames = NULL;
2675 ioc->req_frames = NULL;
2676 ioc->alloc = NULL;
2677 ioc->alloc_total -= sz;
2678 }
2679
2680 if (ioc->sense_buf_pool != NULL) {
2681 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2682 pci_free_consistent(ioc->pcidev, sz,
2683 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2684 ioc->sense_buf_pool = NULL;
2685 ioc->alloc_total -= sz;
2686 }
2687
2688 if (ioc->events != NULL){
2689 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2690 kfree(ioc->events);
2691 ioc->events = NULL;
2692 ioc->alloc_total -= sz;
2693 }
2694
Prakash, Sathya984621b2008-01-11 14:42:17 +05302695 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002697 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002698 mpt_inactive_raid_list_free(ioc);
2699 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002700 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002701 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002702 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703
2704 if (ioc->spi_data.pIocPg4 != NULL) {
2705 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302706 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 ioc->spi_data.pIocPg4,
2708 ioc->spi_data.IocPg4_dma);
2709 ioc->spi_data.pIocPg4 = NULL;
2710 ioc->alloc_total -= sz;
2711 }
2712
2713 if (ioc->ReqToChain != NULL) {
2714 kfree(ioc->ReqToChain);
2715 kfree(ioc->RequestNB);
2716 ioc->ReqToChain = NULL;
2717 }
2718
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002719 kfree(ioc->ChainToChain);
2720 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002721
2722 if (ioc->HostPageBuffer != NULL) {
2723 if((ret = mpt_host_page_access_control(ioc,
2724 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002725 printk(MYIOC_s_ERR_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302726 ": %s: host page buffers free failed (%d)!\n",
2727 ioc->name, __func__, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002728 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302729 dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2730 "HostPageBuffer free @ %p, sz=%d bytes\n",
2731 ioc->name, ioc->HostPageBuffer,
2732 ioc->HostPageBuffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002733 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002734 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002735 ioc->HostPageBuffer = NULL;
2736 ioc->HostPageBuffer_sz = 0;
2737 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2738 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739
Kashyap, Desai2f187862009-05-29 16:52:37 +05302740 pci_set_drvdata(ioc->pcidev, NULL);
2741}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002743/**
2744 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 * @ioc: Pointer to MPT adapter structure
2746 *
2747 * This routine unregisters h/w resources and frees all alloc'd memory
2748 * associated with a MPT adapter structure.
2749 */
2750static void
2751mpt_adapter_dispose(MPT_ADAPTER *ioc)
2752{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002753 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002755 if (ioc == NULL)
2756 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002758 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002760 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002762 if (ioc->pci_irq != -1) {
2763 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302764 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002765 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002766 ioc->pci_irq = -1;
2767 }
2768
2769 if (ioc->memmap != NULL) {
2770 iounmap(ioc->memmap);
2771 ioc->memmap = NULL;
2772 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302774 pci_disable_device(ioc->pcidev);
2775 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2776
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002778 if (ioc->mtrr_reg > 0) {
2779 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002780 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002781 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782#endif
2783
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002784 /* Zap the adapter lookup ptr! */
2785 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002787 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002788 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2789 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002790
2791 if (ioc->alt_ioc)
2792 ioc->alt_ioc->alt_ioc = NULL;
2793
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002794 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795}
2796
2797/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002798/**
2799 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 * @ioc: Pointer to MPT adapter structure
2801 */
2802static void
2803MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2804{
2805 int i = 0;
2806
2807 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302808 if (ioc->prod_name)
2809 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 printk("Capabilities={");
2811
2812 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2813 printk("Initiator");
2814 i++;
2815 }
2816
2817 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2818 printk("%sTarget", i ? "," : "");
2819 i++;
2820 }
2821
2822 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2823 printk("%sLAN", i ? "," : "");
2824 i++;
2825 }
2826
2827#if 0
2828 /*
2829 * This would probably evoke more questions than it's worth
2830 */
2831 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2832 printk("%sLogBusAddr", i ? "," : "");
2833 i++;
2834 }
2835#endif
2836
2837 printk("}\n");
2838}
2839
2840/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002841/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2843 * @ioc: Pointer to MPT_ADAPTER structure
2844 * @force: Force hard KickStart of IOC
2845 * @sleepFlag: Specifies whether the process can sleep
2846 *
2847 * Returns:
2848 * 1 - DIAG reset and READY
2849 * 0 - READY initially OR soft reset and READY
2850 * -1 - Any failure on KickStart
2851 * -2 - Msg Unit Reset Failed
2852 * -3 - IO Unit Reset Failed
2853 * -4 - IOC owned by a PEER
2854 */
2855static int
2856MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2857{
2858 u32 ioc_state;
2859 int statefault = 0;
2860 int cntdn;
2861 int hard_reset_done = 0;
2862 int r;
2863 int ii;
2864 int whoinit;
2865
2866 /* Get current [raw] IOC state */
2867 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002868 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869
2870 /*
2871 * Check to see if IOC got left/stuck in doorbell handshake
2872 * grip of death. If so, hard reset the IOC.
2873 */
2874 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2875 statefault = 1;
2876 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2877 ioc->name);
2878 }
2879
2880 /* Is it already READY? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302881 if (!statefault &&
2882 ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) {
2883 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2884 "IOC is in READY state\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 return 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302886 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887
2888 /*
2889 * Check to see if IOC is in FAULT state.
2890 */
2891 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2892 statefault = 2;
2893 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002894 ioc->name);
2895 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2896 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 }
2898
2899 /*
2900 * Hmmm... Did it get left operational?
2901 */
2902 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302903 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 ioc->name));
2905
2906 /* Check WhoInit.
2907 * If PCI Peer, exit.
2908 * Else, if no fault conditions are present, issue a MessageUnitReset
2909 * Else, fall through to KickStart case
2910 */
2911 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002912 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2913 "whoinit 0x%x statefault %d force %d\n",
2914 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 if (whoinit == MPI_WHOINIT_PCI_PEER)
2916 return -4;
2917 else {
2918 if ((statefault == 0 ) && (force == 0)) {
2919 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2920 return 0;
2921 }
2922 statefault = 3;
2923 }
2924 }
2925
2926 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2927 if (hard_reset_done < 0)
2928 return -1;
2929
2930 /*
2931 * Loop here waiting for IOC to come READY.
2932 */
2933 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002934 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935
2936 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2937 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2938 /*
2939 * BIOS or previous driver load left IOC in OP state.
2940 * Reset messaging FIFOs.
2941 */
2942 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2943 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2944 return -2;
2945 }
2946 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2947 /*
2948 * Something is wrong. Try to get IOC back
2949 * to a known state.
2950 */
2951 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2952 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2953 return -3;
2954 }
2955 }
2956
2957 ii++; cntdn--;
2958 if (!cntdn) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302959 printk(MYIOC_s_ERR_FMT
2960 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
2961 ioc->name, ioc_state, (int)((ii+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 return -ETIME;
2963 }
2964
2965 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002966 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 } else {
2968 mdelay (1); /* 1 msec delay */
2969 }
2970
2971 }
2972
2973 if (statefault < 3) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302974 printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name,
2975 statefault == 1 ? "stuck handshake" : "IOC FAULT");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 }
2977
2978 return hard_reset_done;
2979}
2980
2981/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002982/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 * mpt_GetIocState - Get the current state of a MPT adapter.
2984 * @ioc: Pointer to MPT_ADAPTER structure
2985 * @cooked: Request raw or cooked IOC state
2986 *
2987 * Returns all IOC Doorbell register bits if cooked==0, else just the
2988 * Doorbell bits in MPI_IOC_STATE_MASK.
2989 */
2990u32
2991mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2992{
2993 u32 s, sc;
2994
2995 /* Get! */
2996 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 sc = s & MPI_IOC_STATE_MASK;
2998
2999 /* Save! */
3000 ioc->last_state = sc;
3001
3002 return cooked ? sc : s;
3003}
3004
3005/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003006/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 * GetIocFacts - Send IOCFacts request to MPT adapter.
3008 * @ioc: Pointer to MPT_ADAPTER structure
3009 * @sleepFlag: Specifies whether the process can sleep
3010 * @reason: If recovery, only update facts.
3011 *
3012 * Returns 0 for success, non-zero for failure.
3013 */
3014static int
3015GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
3016{
3017 IOCFacts_t get_facts;
3018 IOCFactsReply_t *facts;
3019 int r;
3020 int req_sz;
3021 int reply_sz;
3022 int sz;
3023 u32 status, vv;
3024 u8 shiftFactor=1;
3025
3026 /* IOC *must* NOT be in RESET state! */
3027 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303028 printk(KERN_ERR MYNAM
3029 ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
3030 ioc->name, ioc->last_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 return -44;
3032 }
3033
3034 facts = &ioc->facts;
3035
3036 /* Destination (reply area)... */
3037 reply_sz = sizeof(*facts);
3038 memset(facts, 0, reply_sz);
3039
3040 /* Request area (get_facts on the stack right now!) */
3041 req_sz = sizeof(get_facts);
3042 memset(&get_facts, 0, req_sz);
3043
3044 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
3045 /* Assert: All other get_facts fields are zero! */
3046
Prakash, Sathya436ace72007-07-24 15:42:08 +05303047 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003048 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049 ioc->name, req_sz, reply_sz));
3050
3051 /* No non-zero fields in the get_facts request are greater than
3052 * 1 byte in size, so we can just fire it off as is.
3053 */
3054 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3055 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3056 if (r != 0)
3057 return r;
3058
3059 /*
3060 * Now byte swap (GRRR) the necessary fields before any further
3061 * inspection of reply contents.
3062 *
3063 * But need to do some sanity checks on MsgLength (byte) field
3064 * to make sure we don't zero IOC's req_sz!
3065 */
3066 /* Did we get a valid reply? */
3067 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3068 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3069 /*
3070 * If not been here, done that, save off first WhoInit value
3071 */
3072 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3073 ioc->FirstWhoInit = facts->WhoInit;
3074 }
3075
3076 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3077 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3078 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3079 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3080 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003081 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 /* CHECKME! IOCStatus, IOCLogInfo */
3083
3084 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3085 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3086
3087 /*
3088 * FC f/w version changed between 1.1 and 1.2
3089 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3090 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3091 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303092 if (facts->MsgVersion < MPI_VERSION_01_02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 /*
3094 * Handle old FC f/w style, convert to new...
3095 */
3096 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3097 facts->FWVersion.Word =
3098 ((oldv<<12) & 0xFF000000) |
3099 ((oldv<<8) & 0x000FFF00);
3100 } else
3101 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3102
3103 facts->ProductID = le16_to_cpu(facts->ProductID);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303104
Eric Mooreb506ade2007-01-29 09:45:37 -07003105 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3106 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3107 ioc->ir_firmware = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303108
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 facts->CurrentHostMfaHighAddr =
3110 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3111 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3112 facts->CurrentSenseBufferHighAddr =
3113 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3114 facts->CurReplyFrameSize =
3115 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003116 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117
3118 /*
3119 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3120 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3121 * to 14 in MPI-1.01.0x.
3122 */
3123 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
Kashyap, Desai2f187862009-05-29 16:52:37 +05303124 facts->MsgVersion > MPI_VERSION_01_00) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3126 }
3127
3128 sz = facts->FWImageSize;
3129 if ( sz & 0x01 )
3130 sz += 1;
3131 if ( sz & 0x02 )
3132 sz += 2;
3133 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003134
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 if (!facts->RequestFrameSize) {
3136 /* Something is wrong! */
3137 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3138 ioc->name);
3139 return -55;
3140 }
3141
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003142 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 vv = ((63 / (sz * 4)) + 1) & 0x03;
3144 ioc->NB_for_64_byte_frame = vv;
3145 while ( sz )
3146 {
3147 shiftFactor++;
3148 sz = sz >> 1;
3149 }
3150 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303151 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003152 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3153 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003154
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3156 /*
3157 * Set values for this IOC's request & reply frame sizes,
3158 * and request & reply queue depths...
3159 */
3160 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3161 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3162 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3163 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3164
Prakash, Sathya436ace72007-07-24 15:42:08 +05303165 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303167 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 ioc->name, ioc->req_sz, ioc->req_depth));
3169
3170 /* Get port facts! */
3171 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3172 return r;
3173 }
3174 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003175 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3177 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3178 RequestFrameSize)/sizeof(u32)));
3179 return -66;
3180 }
3181
3182 return 0;
3183}
3184
3185/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003186/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 * GetPortFacts - Send PortFacts request to MPT adapter.
3188 * @ioc: Pointer to MPT_ADAPTER structure
3189 * @portnum: Port number
3190 * @sleepFlag: Specifies whether the process can sleep
3191 *
3192 * Returns 0 for success, non-zero for failure.
3193 */
3194static int
3195GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3196{
3197 PortFacts_t get_pfacts;
3198 PortFactsReply_t *pfacts;
3199 int ii;
3200 int req_sz;
3201 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003202 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203
3204 /* IOC *must* NOT be in RESET state! */
3205 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003206 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3207 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208 return -4;
3209 }
3210
3211 pfacts = &ioc->pfacts[portnum];
3212
3213 /* Destination (reply area)... */
3214 reply_sz = sizeof(*pfacts);
3215 memset(pfacts, 0, reply_sz);
3216
3217 /* Request area (get_pfacts on the stack right now!) */
3218 req_sz = sizeof(get_pfacts);
3219 memset(&get_pfacts, 0, req_sz);
3220
3221 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3222 get_pfacts.PortNumber = portnum;
3223 /* Assert: All other get_pfacts fields are zero! */
3224
Prakash, Sathya436ace72007-07-24 15:42:08 +05303225 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 ioc->name, portnum));
3227
3228 /* No non-zero fields in the get_pfacts request are greater than
3229 * 1 byte in size, so we can just fire it off as is.
3230 */
3231 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3232 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3233 if (ii != 0)
3234 return ii;
3235
3236 /* Did we get a valid reply? */
3237
3238 /* Now byte swap the necessary fields in the response. */
3239 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3240 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3241 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3242 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3243 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3244 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3245 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3246 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3247 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3248
Eric Moore793955f2007-01-29 09:42:20 -07003249 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3250 pfacts->MaxDevices;
3251 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3252 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3253
3254 /*
3255 * Place all the devices on channels
3256 *
3257 * (for debuging)
3258 */
3259 if (mpt_channel_mapping) {
3260 ioc->devices_per_bus = 1;
3261 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3262 }
3263
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 return 0;
3265}
3266
3267/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003268/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 * SendIocInit - Send IOCInit request to MPT adapter.
3270 * @ioc: Pointer to MPT_ADAPTER structure
3271 * @sleepFlag: Specifies whether the process can sleep
3272 *
3273 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3274 *
3275 * Returns 0 for success, non-zero for failure.
3276 */
3277static int
3278SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3279{
3280 IOCInit_t ioc_init;
3281 MPIDefaultReply_t init_reply;
3282 u32 state;
3283 int r;
3284 int count;
3285 int cntdn;
3286
3287 memset(&ioc_init, 0, sizeof(ioc_init));
3288 memset(&init_reply, 0, sizeof(init_reply));
3289
3290 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3291 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3292
3293 /* If we are in a recovery mode and we uploaded the FW image,
3294 * then this pointer is not NULL. Skip the upload a second time.
3295 * Set this flag if cached_fw set for either IOC.
3296 */
3297 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3298 ioc->upload_fw = 1;
3299 else
3300 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303301 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3303
Eric Moore793955f2007-01-29 09:42:20 -07003304 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3305 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303306
Prakash, Sathya436ace72007-07-24 15:42:08 +05303307 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003308 ioc->name, ioc->facts.MsgVersion));
3309 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3310 // set MsgVersion and HeaderVersion host driver was built with
3311 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3312 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003314 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3315 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3316 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3317 return -99;
3318 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3320
Kashyap, Desai2f187862009-05-29 16:52:37 +05303321 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 /* Save the upper 32-bits of the request
3323 * (reply) and sense buffers.
3324 */
3325 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3326 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3327 } else {
3328 /* Force 32-bit addressing */
3329 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3330 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3331 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003332
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3334 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003335 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3336 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337
Prakash, Sathya436ace72007-07-24 15:42:08 +05303338 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 ioc->name, &ioc_init));
3340
3341 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3342 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003343 if (r != 0) {
3344 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003346 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347
3348 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003349 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350 */
3351
Prakash, Sathya436ace72007-07-24 15:42:08 +05303352 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003354
3355 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3356 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359
3360 /* YIKES! SUPER IMPORTANT!!!
3361 * Poll IocState until _OPERATIONAL while IOC is doing
3362 * LoopInit and TargetDiscovery!
3363 */
3364 count = 0;
3365 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3366 state = mpt_GetIocState(ioc, 1);
3367 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3368 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003369 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 } else {
3371 mdelay(1);
3372 }
3373
3374 if (!cntdn) {
3375 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3376 ioc->name, (int)((count+5)/HZ));
3377 return -9;
3378 }
3379
3380 state = mpt_GetIocState(ioc, 1);
3381 count++;
3382 }
Eric Moore29dd3602007-09-14 18:46:51 -06003383 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 ioc->name, count));
3385
Eric Mooreba856d32006-07-11 17:34:01 -06003386 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 return r;
3388}
3389
3390/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003391/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 * SendPortEnable - Send PortEnable request to MPT adapter port.
3393 * @ioc: Pointer to MPT_ADAPTER structure
3394 * @portnum: Port number to enable
3395 * @sleepFlag: Specifies whether the process can sleep
3396 *
3397 * Send PortEnable to bring IOC to OPERATIONAL state.
3398 *
3399 * Returns 0 for success, non-zero for failure.
3400 */
3401static int
3402SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3403{
3404 PortEnable_t port_enable;
3405 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003406 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 int req_sz;
3408 int reply_sz;
3409
3410 /* Destination... */
3411 reply_sz = sizeof(MPIDefaultReply_t);
3412 memset(&reply_buf, 0, reply_sz);
3413
3414 req_sz = sizeof(PortEnable_t);
3415 memset(&port_enable, 0, req_sz);
3416
3417 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3418 port_enable.PortNumber = portnum;
3419/* port_enable.ChainOffset = 0; */
3420/* port_enable.MsgFlags = 0; */
3421/* port_enable.MsgContext = 0; */
3422
Prakash, Sathya436ace72007-07-24 15:42:08 +05303423 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 ioc->name, portnum, &port_enable));
3425
3426 /* RAID FW may take a long time to enable
3427 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003428 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003429 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3430 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3431 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003432 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003433 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3434 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3435 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003437 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438}
3439
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003440/**
3441 * mpt_alloc_fw_memory - allocate firmware memory
3442 * @ioc: Pointer to MPT_ADAPTER structure
3443 * @size: total FW bytes
3444 *
3445 * If memory has already been allocated, the same (cached) value
3446 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303447 *
3448 * Return 0 if successfull, or non-zero for failure
3449 **/
3450int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3452{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303453 int rc;
3454
3455 if (ioc->cached_fw) {
3456 rc = 0; /* use already allocated memory */
3457 goto out;
3458 }
3459 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3461 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303462 rc = 0;
3463 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303465 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3466 if (!ioc->cached_fw) {
3467 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3468 ioc->name);
3469 rc = -1;
3470 } else {
3471 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3472 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3473 ioc->alloc_total += size;
3474 rc = 0;
3475 }
3476 out:
3477 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303479
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003480/**
3481 * mpt_free_fw_memory - free firmware memory
3482 * @ioc: Pointer to MPT_ADAPTER structure
3483 *
3484 * If alt_img is NULL, delete from ioc structure.
3485 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303486 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487void
3488mpt_free_fw_memory(MPT_ADAPTER *ioc)
3489{
3490 int sz;
3491
Prakash, Sathya984621b2008-01-11 14:42:17 +05303492 if (!ioc->cached_fw)
3493 return;
3494
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303496 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3497 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003498 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303499 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501}
3502
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003504/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3506 * @ioc: Pointer to MPT_ADAPTER structure
3507 * @sleepFlag: Specifies whether the process can sleep
3508 *
3509 * Returns 0 for success, >0 for handshake failure
3510 * <0 for fw upload failure.
3511 *
3512 * Remark: If bound IOC and a successful FWUpload was performed
3513 * on the bound IOC, the second image is discarded
3514 * and memory is free'd. Both channels must upload to prevent
3515 * IOC from running in degraded mode.
3516 */
3517static int
3518mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3519{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 u8 reply[sizeof(FWUploadReply_t)];
3521 FWUpload_t *prequest;
3522 FWUploadReply_t *preply;
3523 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 u32 flagsLength;
3525 int ii, sz, reply_sz;
3526 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303527 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 /* If the image size is 0, we are done.
3529 */
3530 if ((sz = ioc->facts.FWImageSize) == 0)
3531 return 0;
3532
Prakash, Sathya984621b2008-01-11 14:42:17 +05303533 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3534 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535
Eric Moore29dd3602007-09-14 18:46:51 -06003536 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3537 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003538
Eric Moorebc6e0892007-09-29 10:16:28 -06003539 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3540 kzalloc(ioc->req_sz, GFP_KERNEL);
3541 if (!prequest) {
3542 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3543 "while allocating memory \n", ioc->name));
3544 mpt_free_fw_memory(ioc);
3545 return -ENOMEM;
3546 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547
Eric Moorebc6e0892007-09-29 10:16:28 -06003548 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549
3550 reply_sz = sizeof(reply);
3551 memset(preply, 0, reply_sz);
3552
3553 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3554 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3555
3556 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3557 ptcsge->DetailsLength = 12;
3558 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3559 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003560 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303563 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3564 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3565 ioc->SGE_size;
3566 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3567 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3568 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003569 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303571 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3572 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573
Kashyap, Desai2f187862009-05-29 16:52:37 +05303574 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
3575 "rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576
3577 cmdStatus = -EFAULT;
3578 if (ii == 0) {
3579 /* Handshake transfer was complete and successful.
3580 * Check the Reply Frame.
3581 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303582 int status;
3583 status = le16_to_cpu(preply->IOCStatus) &
3584 MPI_IOCSTATUS_MASK;
3585 if (status == MPI_IOCSTATUS_SUCCESS &&
3586 ioc->facts.FWImageSize ==
3587 le32_to_cpu(preply->ActualImageSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 cmdStatus = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303590 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 ioc->name, cmdStatus));
3592
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003593
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 if (cmdStatus) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303595 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
3596 "freeing image \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 mpt_free_fw_memory(ioc);
3598 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003599 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600
3601 return cmdStatus;
3602}
3603
3604/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003605/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 * mpt_downloadboot - DownloadBoot code
3607 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003608 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 * @sleepFlag: Specifies whether the process can sleep
3610 *
3611 * FwDownloadBoot requires Programmed IO access.
3612 *
3613 * Returns 0 for success
3614 * -1 FW Image size is 0
3615 * -2 No valid cached_fw Pointer
3616 * <0 for fw upload failure.
3617 */
3618static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003619mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 MpiExtImageHeader_t *pExtImage;
3622 u32 fwSize;
3623 u32 diag0val;
3624 int count;
3625 u32 *ptrFw;
3626 u32 diagRwData;
3627 u32 nextImage;
3628 u32 load_addr;
3629 u32 ioc_state=0;
3630
Prakash, Sathya436ace72007-07-24 15:42:08 +05303631 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003632 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003633
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3635 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3636 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3637 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3638 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3639 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3640
3641 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3642
3643 /* wait 1 msec */
3644 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003645 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 } else {
3647 mdelay (1);
3648 }
3649
3650 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3651 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3652
3653 for (count = 0; count < 30; count ++) {
3654 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3655 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303656 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 ioc->name, count));
3658 break;
3659 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003660 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003662 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003664 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 }
3666 }
3667
3668 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303669 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003670 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 ioc->name, diag0val));
3672 return -3;
3673 }
3674
3675 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3676 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3677 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3678 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3679 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3680 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3681
3682 /* Set the DiagRwEn and Disable ARM bits */
3683 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3684
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685 fwSize = (pFwHeader->ImageSize + 3)/4;
3686 ptrFw = (u32 *) pFwHeader;
3687
3688 /* Write the LoadStartAddress to the DiagRw Address Register
3689 * using Programmed IO
3690 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003691 if (ioc->errata_flag_1064)
3692 pci_enable_io_access(ioc->pcidev);
3693
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303695 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696 ioc->name, pFwHeader->LoadStartAddress));
3697
Prakash, Sathya436ace72007-07-24 15:42:08 +05303698 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699 ioc->name, fwSize*4, ptrFw));
3700 while (fwSize--) {
3701 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3702 }
3703
3704 nextImage = pFwHeader->NextImageHeaderOffset;
3705 while (nextImage) {
3706 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3707
3708 load_addr = pExtImage->LoadStartAddress;
3709
3710 fwSize = (pExtImage->ImageSize + 3) >> 2;
3711 ptrFw = (u32 *)pExtImage;
3712
Prakash, Sathya436ace72007-07-24 15:42:08 +05303713 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 +02003714 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3716
3717 while (fwSize--) {
3718 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3719 }
3720 nextImage = pExtImage->NextImageHeaderOffset;
3721 }
3722
3723 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303724 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3726
3727 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303728 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3730
3731 /* Clear the internal flash bad bit - autoincrementing register,
3732 * so must do two writes.
3733 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003734 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003735 /*
3736 * 1030 and 1035 H/W errata, workaround to access
3737 * the ClearFlashBadSignatureBit
3738 */
3739 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3740 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3741 diagRwData |= 0x40000000;
3742 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3743 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3744
3745 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3746 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3747 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3748 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3749
3750 /* wait 1 msec */
3751 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003752 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003753 } else {
3754 mdelay (1);
3755 }
3756 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003758 if (ioc->errata_flag_1064)
3759 pci_disable_io_access(ioc->pcidev);
3760
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303762 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003763 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003765 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303766 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767 ioc->name, diag0val));
3768 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3769
3770 /* Write 0xFF to reset the sequencer */
3771 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3772
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003773 if (ioc->bus_type == SAS) {
3774 ioc_state = mpt_GetIocState(ioc, 0);
3775 if ( (GetIocFacts(ioc, sleepFlag,
3776 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303777 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003778 ioc->name, ioc_state));
3779 return -EFAULT;
3780 }
3781 }
3782
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783 for (count=0; count<HZ*20; count++) {
3784 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303785 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3786 "downloadboot successful! (count=%d) IocState=%x\n",
3787 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003788 if (ioc->bus_type == SAS) {
3789 return 0;
3790 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303792 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3793 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 ioc->name));
3795 return -EFAULT;
3796 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303797 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3798 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 ioc->name));
3800 return 0;
3801 }
3802 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003803 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804 } else {
3805 mdelay (10);
3806 }
3807 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303808 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3809 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810 return -EFAULT;
3811}
3812
3813/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003814/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 * KickStart - Perform hard reset of MPT adapter.
3816 * @ioc: Pointer to MPT_ADAPTER structure
3817 * @force: Force hard reset
3818 * @sleepFlag: Specifies whether the process can sleep
3819 *
3820 * This routine places MPT adapter in diagnostic mode via the
3821 * WriteSequence register, and then performs a hard reset of adapter
3822 * via the Diagnostic register.
3823 *
3824 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3825 * or NO_SLEEP (interrupt thread, use mdelay)
3826 * force - 1 if doorbell active, board fault state
3827 * board operational, IOC_RECOVERY or
3828 * IOC_BRINGUP and there is an alt_ioc.
3829 * 0 else
3830 *
3831 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003832 * 1 - hard reset, READY
3833 * 0 - no reset due to History bit, READY
3834 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835 * OR reset but failed to come READY
3836 * -2 - no reset, could not enter DIAG mode
3837 * -3 - reset but bad FW bit
3838 */
3839static int
3840KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3841{
3842 int hard_reset_done = 0;
3843 u32 ioc_state=0;
3844 int cnt,cntdn;
3845
Eric Moore29dd3602007-09-14 18:46:51 -06003846 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003847 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848 /* Always issue a Msg Unit Reset first. This will clear some
3849 * SCSI bus hang conditions.
3850 */
3851 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3852
3853 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003854 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855 } else {
3856 mdelay (1000);
3857 }
3858 }
3859
3860 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3861 if (hard_reset_done < 0)
3862 return hard_reset_done;
3863
Prakash, Sathya436ace72007-07-24 15:42:08 +05303864 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003865 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866
3867 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3868 for (cnt=0; cnt<cntdn; cnt++) {
3869 ioc_state = mpt_GetIocState(ioc, 1);
3870 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303871 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 ioc->name, cnt));
3873 return hard_reset_done;
3874 }
3875 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003876 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 } else {
3878 mdelay (10);
3879 }
3880 }
3881
Eric Moore29dd3602007-09-14 18:46:51 -06003882 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3883 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 return -1;
3885}
3886
3887/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003888/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889 * mpt_diag_reset - Perform hard reset of the adapter.
3890 * @ioc: Pointer to MPT_ADAPTER structure
3891 * @ignore: Set if to honor and clear to ignore
3892 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003893 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894 * else set to NO_SLEEP (use mdelay instead)
3895 *
3896 * This routine places the adapter in diagnostic mode via the
3897 * WriteSequence register and then performs a hard reset of adapter
3898 * via the Diagnostic register. Adapter should be in ready state
3899 * upon successful completion.
3900 *
3901 * Returns: 1 hard reset successful
3902 * 0 no reset performed because reset history bit set
3903 * -2 enabling diagnostic mode failed
3904 * -3 diagnostic reset failed
3905 */
3906static int
3907mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3908{
3909 u32 diag0val;
3910 u32 doorbell;
3911 int hard_reset_done = 0;
3912 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303914 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Kashyap, Desaid1306912009-08-05 12:53:51 +05303915 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916
Eric Moorecd2c6192007-01-29 09:47:47 -07003917 /* Clear any existing interrupts */
3918 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3919
Eric Moore87cf8982006-06-27 16:09:26 -06003920 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303921
3922 if (!ignore)
3923 return 0;
3924
Prakash, Sathya436ace72007-07-24 15:42:08 +05303925 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003926 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003927 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3928 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3929 if (sleepFlag == CAN_SLEEP)
3930 msleep(1);
3931 else
3932 mdelay(1);
3933
Kashyap, Desaid1306912009-08-05 12:53:51 +05303934 /*
3935 * Call each currently registered protocol IOC reset handler
3936 * with pre-reset indication.
3937 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3938 * MptResetHandlers[] registered yet.
3939 */
3940 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3941 if (MptResetHandlers[cb_idx])
3942 (*(MptResetHandlers[cb_idx]))(ioc,
3943 MPT_IOC_PRE_RESET);
3944 }
3945
Eric Moore87cf8982006-06-27 16:09:26 -06003946 for (count = 0; count < 60; count ++) {
3947 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3948 doorbell &= MPI_IOC_STATE_MASK;
3949
Prakash, Sathya436ace72007-07-24 15:42:08 +05303950 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003951 "looking for READY STATE: doorbell=%x"
3952 " count=%d\n",
3953 ioc->name, doorbell, count));
Kashyap, Desai2f187862009-05-29 16:52:37 +05303954
Eric Moore87cf8982006-06-27 16:09:26 -06003955 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003956 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003957 }
3958
3959 /* wait 1 sec */
3960 if (sleepFlag == CAN_SLEEP)
3961 msleep(1000);
3962 else
3963 mdelay(1000);
3964 }
3965 return -1;
3966 }
3967
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968 /* Use "Diagnostic reset" method! (only thing available!) */
3969 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3970
Prakash, Sathya436ace72007-07-24 15:42:08 +05303971 if (ioc->debug_level & MPT_DEBUG) {
3972 if (ioc->alt_ioc)
3973 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3974 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303976 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977
3978 /* Do the reset if we are told to ignore the reset history
3979 * or if the reset history is 0
3980 */
3981 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3982 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3983 /* Write magic sequence to WriteSequence register
3984 * Loop until in diagnostic mode
3985 */
3986 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3987 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3988 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3989 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3990 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3991 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3992
3993 /* wait 100 msec */
3994 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003995 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 } else {
3997 mdelay (100);
3998 }
3999
4000 count++;
4001 if (count > 20) {
4002 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4003 ioc->name, diag0val);
4004 return -2;
4005
4006 }
4007
4008 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4009
Prakash, Sathya436ace72007-07-24 15:42:08 +05304010 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 ioc->name, diag0val));
4012 }
4013
Prakash, Sathya436ace72007-07-24 15:42:08 +05304014 if (ioc->debug_level & MPT_DEBUG) {
4015 if (ioc->alt_ioc)
4016 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4017 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304019 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020 /*
4021 * Disable the ARM (Bug fix)
4022 *
4023 */
4024 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004025 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026
4027 /*
4028 * Now hit the reset bit in the Diagnostic register
4029 * (THE BIG HAMMER!) (Clears DRWE bit).
4030 */
4031 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
4032 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304033 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 ioc->name));
4035
4036 /*
4037 * Call each currently registered protocol IOC reset handler
4038 * with pre-reset indication.
4039 * NOTE: If we're doing _IOC_BRINGUP, there can be no
4040 * MptResetHandlers[] registered yet.
4041 */
Kashyap, Desaid1306912009-08-05 12:53:51 +05304042 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
4043 if (MptResetHandlers[cb_idx]) {
4044 mpt_signal_reset(cb_idx,
4045 ioc, MPT_IOC_PRE_RESET);
4046 if (ioc->alt_ioc) {
4047 mpt_signal_reset(cb_idx,
4048 ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 }
4050 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 }
4052
Eric Moore0ccdb002006-07-11 17:33:13 -06004053 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304054 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06004055 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304056 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4057 else
4058 cached_fw = NULL;
4059 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 /* If the DownloadBoot operation fails, the
4061 * IOC will be left unusable. This is a fatal error
4062 * case. _diag_reset will return < 0
4063 */
4064 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304065 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4067 break;
4068 }
4069
Prakash, Sathya436ace72007-07-24 15:42:08 +05304070 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304071 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072 /* wait 1 sec */
4073 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004074 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075 } else {
4076 mdelay (1000);
4077 }
4078 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304079 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004080 printk(MYIOC_s_WARN_FMT
4081 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004082 }
4083
4084 } else {
4085 /* Wait for FW to reload and for board
4086 * to go to the READY state.
4087 * Maximum wait is 60 seconds.
4088 * If fail, no error will check again
4089 * with calling program.
4090 */
4091 for (count = 0; count < 60; count ++) {
4092 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4093 doorbell &= MPI_IOC_STATE_MASK;
4094
Kashyap, Desai2f187862009-05-29 16:52:37 +05304095 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4096 "looking for READY STATE: doorbell=%x"
4097 " count=%d\n", ioc->name, doorbell, count));
4098
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099 if (doorbell == MPI_IOC_STATE_READY) {
4100 break;
4101 }
4102
4103 /* wait 1 sec */
4104 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004105 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106 } else {
4107 mdelay (1000);
4108 }
4109 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05304110
4111 if (doorbell != MPI_IOC_STATE_READY)
4112 printk(MYIOC_s_ERR_FMT "Failed to come READY "
4113 "after reset! IocState=%x", ioc->name,
4114 doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115 }
4116 }
4117
4118 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304119 if (ioc->debug_level & MPT_DEBUG) {
4120 if (ioc->alt_ioc)
4121 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4122 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4123 ioc->name, diag0val, diag1val));
4124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125
4126 /* Clear RESET_HISTORY bit! Place board in the
4127 * diagnostic mode to update the diag register.
4128 */
4129 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4130 count = 0;
4131 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4132 /* Write magic sequence to WriteSequence register
4133 * Loop until in diagnostic mode
4134 */
4135 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4136 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4137 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4138 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4139 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4140 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4141
4142 /* wait 100 msec */
4143 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004144 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 } else {
4146 mdelay (100);
4147 }
4148
4149 count++;
4150 if (count > 20) {
4151 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4152 ioc->name, diag0val);
4153 break;
4154 }
4155 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4156 }
4157 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4158 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4159 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4160 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4161 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4162 ioc->name);
4163 }
4164
4165 /* Disable Diagnostic Mode
4166 */
4167 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4168
4169 /* Check FW reload status flags.
4170 */
4171 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4172 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4173 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4174 ioc->name, diag0val);
4175 return -3;
4176 }
4177
Prakash, Sathya436ace72007-07-24 15:42:08 +05304178 if (ioc->debug_level & MPT_DEBUG) {
4179 if (ioc->alt_ioc)
4180 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4181 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184
4185 /*
4186 * Reset flag that says we've enabled event notification
4187 */
4188 ioc->facts.EventState = 0;
4189
4190 if (ioc->alt_ioc)
4191 ioc->alt_ioc->facts.EventState = 0;
4192
4193 return hard_reset_done;
4194}
4195
4196/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004197/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198 * SendIocReset - Send IOCReset request to MPT adapter.
4199 * @ioc: Pointer to MPT_ADAPTER structure
4200 * @reset_type: reset type, expected values are
4201 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004202 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203 *
4204 * Send IOCReset request to the MPT adapter.
4205 *
4206 * Returns 0 for success, non-zero for failure.
4207 */
4208static int
4209SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4210{
4211 int r;
4212 u32 state;
4213 int cntdn, count;
4214
Prakash, Sathya436ace72007-07-24 15:42:08 +05304215 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216 ioc->name, reset_type));
4217 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4218 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4219 return r;
4220
4221 /* FW ACK'd request, wait for READY state
4222 */
4223 count = 0;
4224 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4225
4226 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4227 cntdn--;
4228 count++;
4229 if (!cntdn) {
4230 if (sleepFlag != CAN_SLEEP)
4231 count *= 10;
4232
Kashyap, Desai2f187862009-05-29 16:52:37 +05304233 printk(MYIOC_s_ERR_FMT
4234 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
4235 ioc->name, state, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236 return -ETIME;
4237 }
4238
4239 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004240 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241 } else {
4242 mdelay (1); /* 1 msec delay */
4243 }
4244 }
4245
4246 /* TODO!
4247 * Cleanup all event stuff for this IOC; re-issue EventNotification
4248 * request if needed.
4249 */
4250 if (ioc->facts.Function)
4251 ioc->facts.EventState = 0;
4252
4253 return 0;
4254}
4255
4256/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004257/**
4258 * initChainBuffers - Allocate memory for and initialize chain buffers
4259 * @ioc: Pointer to MPT_ADAPTER structure
4260 *
4261 * Allocates memory for and initializes chain buffers,
4262 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 */
4264static int
4265initChainBuffers(MPT_ADAPTER *ioc)
4266{
4267 u8 *mem;
4268 int sz, ii, num_chain;
4269 int scale, num_sge, numSGE;
4270
4271 /* ReqToChain size must equal the req_depth
4272 * index = req_idx
4273 */
4274 if (ioc->ReqToChain == NULL) {
4275 sz = ioc->req_depth * sizeof(int);
4276 mem = kmalloc(sz, GFP_ATOMIC);
4277 if (mem == NULL)
4278 return -1;
4279
4280 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304281 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 ioc->name, mem, sz));
4283 mem = kmalloc(sz, GFP_ATOMIC);
4284 if (mem == NULL)
4285 return -1;
4286
4287 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304288 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 ioc->name, mem, sz));
4290 }
4291 for (ii = 0; ii < ioc->req_depth; ii++) {
4292 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4293 }
4294
4295 /* ChainToChain size must equal the total number
4296 * of chain buffers to be allocated.
4297 * index = chain_idx
4298 *
4299 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004300 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 *
4302 * num_sge = num sge in request frame + last chain buffer
4303 * scale = num sge per chain buffer if no chain element
4304 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304305 scale = ioc->req_sz / ioc->SGE_size;
4306 if (ioc->sg_addr_size == sizeof(u64))
4307 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304309 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304311 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304313 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304315 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4316 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304318 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319 ioc->name, num_sge, numSGE));
4320
Kashyap, Desai2f187862009-05-29 16:52:37 +05304321 if (ioc->bus_type == FC) {
4322 if (numSGE > MPT_SCSI_FC_SG_DEPTH)
4323 numSGE = MPT_SCSI_FC_SG_DEPTH;
4324 } else {
4325 if (numSGE > MPT_SCSI_SG_DEPTH)
4326 numSGE = MPT_SCSI_SG_DEPTH;
4327 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328
4329 num_chain = 1;
4330 while (numSGE - num_sge > 0) {
4331 num_chain++;
4332 num_sge += (scale - 1);
4333 }
4334 num_chain++;
4335
Prakash, Sathya436ace72007-07-24 15:42:08 +05304336 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337 ioc->name, numSGE, num_sge, num_chain));
4338
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004339 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 num_chain *= MPT_SCSI_CAN_QUEUE;
Anatolij Gustschinf1053a72009-12-12 14:52:21 +01004341 else if (ioc->bus_type == SAS)
4342 num_chain *= MPT_SAS_CAN_QUEUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 else
4344 num_chain *= MPT_FC_CAN_QUEUE;
4345
4346 ioc->num_chain = num_chain;
4347
4348 sz = num_chain * sizeof(int);
4349 if (ioc->ChainToChain == NULL) {
4350 mem = kmalloc(sz, GFP_ATOMIC);
4351 if (mem == NULL)
4352 return -1;
4353
4354 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304355 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 ioc->name, mem, sz));
4357 } else {
4358 mem = (u8 *) ioc->ChainToChain;
4359 }
4360 memset(mem, 0xFF, sz);
4361 return num_chain;
4362}
4363
4364/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004365/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4367 * @ioc: Pointer to MPT_ADAPTER structure
4368 *
4369 * This routine allocates memory for the MPT reply and request frame
4370 * pools (if necessary), and primes the IOC reply FIFO with
4371 * reply frames.
4372 *
4373 * Returns 0 for success, non-zero for failure.
4374 */
4375static int
4376PrimeIocFifos(MPT_ADAPTER *ioc)
4377{
4378 MPT_FRAME_HDR *mf;
4379 unsigned long flags;
4380 dma_addr_t alloc_dma;
4381 u8 *mem;
4382 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304383 u64 dma_mask;
4384
4385 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386
4387 /* Prime reply FIFO... */
4388
4389 if (ioc->reply_frames == NULL) {
4390 if ( (num_chain = initChainBuffers(ioc)) < 0)
4391 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304392 /*
4393 * 1078 errata workaround for the 36GB limitation
4394 */
4395 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
Andrew Morton8e20ce92009-06-18 16:49:17 -07004396 ioc->dma_mask > DMA_BIT_MASK(35)) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304397 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4398 && !pci_set_consistent_dma_mask(ioc->pcidev,
4399 DMA_BIT_MASK(32))) {
Andrew Morton8e20ce92009-06-18 16:49:17 -07004400 dma_mask = DMA_BIT_MASK(35);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304401 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4402 "setting 35 bit addressing for "
4403 "Request/Reply/Chain and Sense Buffers\n",
4404 ioc->name));
4405 } else {
4406 /*Reseting DMA mask to 64 bit*/
4407 pci_set_dma_mask(ioc->pcidev,
4408 DMA_BIT_MASK(64));
4409 pci_set_consistent_dma_mask(ioc->pcidev,
4410 DMA_BIT_MASK(64));
4411
4412 printk(MYIOC_s_ERR_FMT
4413 "failed setting 35 bit addressing for "
4414 "Request/Reply/Chain and Sense Buffers\n",
4415 ioc->name);
4416 return -1;
4417 }
4418 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419
4420 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304421 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304423 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 ioc->name, reply_sz, reply_sz));
4425
4426 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304427 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304429 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 ioc->name, sz, sz));
4431 total_size += sz;
4432
4433 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304434 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304436 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 ioc->name, sz, sz, num_chain));
4438
4439 total_size += sz;
4440 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4441 if (mem == NULL) {
4442 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4443 ioc->name);
4444 goto out_fail;
4445 }
4446
Prakash, Sathya436ace72007-07-24 15:42:08 +05304447 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4449
4450 memset(mem, 0, total_size);
4451 ioc->alloc_total += total_size;
4452 ioc->alloc = mem;
4453 ioc->alloc_dma = alloc_dma;
4454 ioc->alloc_sz = total_size;
4455 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4456 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4457
Prakash, Sathya436ace72007-07-24 15:42:08 +05304458 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004459 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4460
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 alloc_dma += reply_sz;
4462 mem += reply_sz;
4463
4464 /* Request FIFO - WE manage this! */
4465
4466 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4467 ioc->req_frames_dma = alloc_dma;
4468
Prakash, Sathya436ace72007-07-24 15:42:08 +05304469 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 ioc->name, mem, (void *)(ulong)alloc_dma));
4471
4472 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4473
4474#if defined(CONFIG_MTRR) && 0
4475 /*
4476 * Enable Write Combining MTRR for IOC's memory region.
4477 * (at least as much as we can; "size and base must be
4478 * multiples of 4 kiB"
4479 */
4480 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4481 sz,
4482 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304483 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 ioc->name, ioc->req_frames_dma, sz));
4485#endif
4486
4487 for (i = 0; i < ioc->req_depth; i++) {
4488 alloc_dma += ioc->req_sz;
4489 mem += ioc->req_sz;
4490 }
4491
4492 ioc->ChainBuffer = mem;
4493 ioc->ChainBufferDMA = alloc_dma;
4494
Prakash, Sathya436ace72007-07-24 15:42:08 +05304495 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4497
4498 /* Initialize the free chain Q.
4499 */
4500
4501 INIT_LIST_HEAD(&ioc->FreeChainQ);
4502
4503 /* Post the chain buffers to the FreeChainQ.
4504 */
4505 mem = (u8 *)ioc->ChainBuffer;
4506 for (i=0; i < num_chain; i++) {
4507 mf = (MPT_FRAME_HDR *) mem;
4508 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4509 mem += ioc->req_sz;
4510 }
4511
4512 /* Initialize Request frames linked list
4513 */
4514 alloc_dma = ioc->req_frames_dma;
4515 mem = (u8 *) ioc->req_frames;
4516
4517 spin_lock_irqsave(&ioc->FreeQlock, flags);
4518 INIT_LIST_HEAD(&ioc->FreeQ);
4519 for (i = 0; i < ioc->req_depth; i++) {
4520 mf = (MPT_FRAME_HDR *) mem;
4521
4522 /* Queue REQUESTs *internally*! */
4523 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4524
4525 mem += ioc->req_sz;
4526 }
4527 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4528
4529 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4530 ioc->sense_buf_pool =
4531 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4532 if (ioc->sense_buf_pool == NULL) {
4533 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4534 ioc->name);
4535 goto out_fail;
4536 }
4537
4538 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4539 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304540 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4542
4543 }
4544
4545 /* Post Reply frames to FIFO
4546 */
4547 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304548 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4550
4551 for (i = 0; i < ioc->reply_depth; i++) {
4552 /* Write each address to the IOC! */
4553 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4554 alloc_dma += ioc->reply_sz;
4555 }
4556
Andrew Morton8e20ce92009-06-18 16:49:17 -07004557 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304558 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4559 ioc->dma_mask))
4560 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4561 "restoring 64 bit addressing\n", ioc->name));
4562
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 return 0;
4564
4565out_fail:
Kashyap, Desai2f187862009-05-29 16:52:37 +05304566
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 if (ioc->alloc != NULL) {
4568 sz = ioc->alloc_sz;
4569 pci_free_consistent(ioc->pcidev,
4570 sz,
4571 ioc->alloc, ioc->alloc_dma);
4572 ioc->reply_frames = NULL;
4573 ioc->req_frames = NULL;
4574 ioc->alloc_total -= sz;
4575 }
4576 if (ioc->sense_buf_pool != NULL) {
4577 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4578 pci_free_consistent(ioc->pcidev,
4579 sz,
4580 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4581 ioc->sense_buf_pool = NULL;
4582 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304583
Andrew Morton8e20ce92009-06-18 16:49:17 -07004584 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304585 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4586 DMA_BIT_MASK(64)))
4587 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4588 "restoring 64 bit addressing\n", ioc->name));
4589
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 return -1;
4591}
4592
4593/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4594/**
4595 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4596 * from IOC via doorbell handshake method.
4597 * @ioc: Pointer to MPT_ADAPTER structure
4598 * @reqBytes: Size of the request in bytes
4599 * @req: Pointer to MPT request frame
4600 * @replyBytes: Expected size of the reply in bytes
4601 * @u16reply: Pointer to area where reply should be written
4602 * @maxwait: Max wait time for a reply (in seconds)
4603 * @sleepFlag: Specifies whether the process can sleep
4604 *
4605 * NOTES: It is the callers responsibility to byte-swap fields in the
4606 * request which are greater than 1 byte in size. It is also the
4607 * callers responsibility to byte-swap response fields which are
4608 * greater than 1 byte in size.
4609 *
4610 * Returns 0 for success, non-zero for failure.
4611 */
4612static int
4613mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004614 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615{
4616 MPIDefaultReply_t *mptReply;
4617 int failcnt = 0;
4618 int t;
4619
4620 /*
4621 * Get ready to cache a handshake reply
4622 */
4623 ioc->hs_reply_idx = 0;
4624 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4625 mptReply->MsgLength = 0;
4626
4627 /*
4628 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4629 * then tell IOC that we want to handshake a request of N words.
4630 * (WRITE u32val to Doorbell reg).
4631 */
4632 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4633 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4634 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4635 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4636
4637 /*
4638 * Wait for IOC's doorbell handshake int
4639 */
4640 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4641 failcnt++;
4642
Prakash, Sathya436ace72007-07-24 15:42:08 +05304643 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4645
4646 /* Read doorbell and check for active bit */
4647 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4648 return -1;
4649
4650 /*
4651 * Clear doorbell int (WRITE 0 to IntStatus reg),
4652 * then wait for IOC to ACKnowledge that it's ready for
4653 * our handshake request.
4654 */
4655 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4656 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4657 failcnt++;
4658
4659 if (!failcnt) {
4660 int ii;
4661 u8 *req_as_bytes = (u8 *) req;
4662
4663 /*
4664 * Stuff request words via doorbell handshake,
4665 * with ACK from IOC for each.
4666 */
4667 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4668 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4669 (req_as_bytes[(ii*4) + 1] << 8) |
4670 (req_as_bytes[(ii*4) + 2] << 16) |
4671 (req_as_bytes[(ii*4) + 3] << 24));
4672
4673 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4674 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4675 failcnt++;
4676 }
4677
Prakash, Sathya436ace72007-07-24 15:42:08 +05304678 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004679 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680
Prakash, Sathya436ace72007-07-24 15:42:08 +05304681 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4683
4684 /*
4685 * Wait for completion of doorbell handshake reply from the IOC
4686 */
4687 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4688 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004689
Prakash, Sathya436ace72007-07-24 15:42:08 +05304690 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4692
4693 /*
4694 * Copy out the cached reply...
4695 */
4696 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4697 u16reply[ii] = ioc->hs_reply[ii];
4698 } else {
4699 return -99;
4700 }
4701
4702 return -failcnt;
4703}
4704
4705/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004706/**
4707 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 * @ioc: Pointer to MPT_ADAPTER structure
4709 * @howlong: How long to wait (in seconds)
4710 * @sleepFlag: Specifies whether the process can sleep
4711 *
4712 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004713 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4714 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715 *
4716 * Returns a negative value on failure, else wait loop count.
4717 */
4718static int
4719WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4720{
4721 int cntdn;
4722 int count = 0;
4723 u32 intstat=0;
4724
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004725 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726
4727 if (sleepFlag == CAN_SLEEP) {
4728 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004729 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4731 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4732 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733 count++;
4734 }
4735 } else {
4736 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004737 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4739 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4740 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741 count++;
4742 }
4743 }
4744
4745 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304746 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 ioc->name, count));
4748 return count;
4749 }
4750
4751 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4752 ioc->name, count, intstat);
4753 return -1;
4754}
4755
4756/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004757/**
4758 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 * @ioc: Pointer to MPT_ADAPTER structure
4760 * @howlong: How long to wait (in seconds)
4761 * @sleepFlag: Specifies whether the process can sleep
4762 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004763 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4764 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 *
4766 * Returns a negative value on failure, else wait loop count.
4767 */
4768static int
4769WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4770{
4771 int cntdn;
4772 int count = 0;
4773 u32 intstat=0;
4774
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004775 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 if (sleepFlag == CAN_SLEEP) {
4777 while (--cntdn) {
4778 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4779 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4780 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004781 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 count++;
4783 }
4784 } else {
4785 while (--cntdn) {
4786 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4787 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4788 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004789 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 count++;
4791 }
4792 }
4793
4794 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304795 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796 ioc->name, count, howlong));
4797 return count;
4798 }
4799
4800 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4801 ioc->name, count, intstat);
4802 return -1;
4803}
4804
4805/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004806/**
4807 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808 * @ioc: Pointer to MPT_ADAPTER structure
4809 * @howlong: How long to wait (in seconds)
4810 * @sleepFlag: Specifies whether the process can sleep
4811 *
4812 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4813 * Reply is cached to IOC private area large enough to hold a maximum
4814 * of 128 bytes of reply data.
4815 *
4816 * Returns a negative value on failure, else size of reply in WORDS.
4817 */
4818static int
4819WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4820{
4821 int u16cnt = 0;
4822 int failcnt = 0;
4823 int t;
4824 u16 *hs_reply = ioc->hs_reply;
4825 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4826 u16 hword;
4827
4828 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4829
4830 /*
4831 * Get first two u16's so we can look at IOC's intended reply MsgLength
4832 */
4833 u16cnt=0;
4834 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4835 failcnt++;
4836 } else {
4837 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4838 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4839 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4840 failcnt++;
4841 else {
4842 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4843 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4844 }
4845 }
4846
Prakash, Sathya436ace72007-07-24 15:42:08 +05304847 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004848 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4850
4851 /*
4852 * If no error (and IOC said MsgLength is > 0), piece together
4853 * reply 16 bits at a time.
4854 */
4855 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4856 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4857 failcnt++;
4858 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4859 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004860 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004861 hs_reply[u16cnt] = hword;
4862 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4863 }
4864
4865 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4866 failcnt++;
4867 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4868
4869 if (failcnt) {
4870 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4871 ioc->name);
4872 return -failcnt;
4873 }
4874#if 0
4875 else if (u16cnt != (2 * mptReply->MsgLength)) {
4876 return -101;
4877 }
4878 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4879 return -102;
4880 }
4881#endif
4882
Prakash, Sathya436ace72007-07-24 15:42:08 +05304883 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004884 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885
Prakash, Sathya436ace72007-07-24 15:42:08 +05304886 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004887 ioc->name, t, u16cnt/2));
4888 return u16cnt/2;
4889}
4890
4891/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004892/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 * GetLanConfigPages - Fetch LANConfig pages.
4894 * @ioc: Pointer to MPT_ADAPTER structure
4895 *
4896 * Return: 0 for success
4897 * -ENOMEM if no memory available
4898 * -EPERM if not allowed due to ISR context
4899 * -EAGAIN if no msg frames currently available
4900 * -EFAULT for non-successful reply or no reply (timeout)
4901 */
4902static int
4903GetLanConfigPages(MPT_ADAPTER *ioc)
4904{
4905 ConfigPageHeader_t hdr;
4906 CONFIGPARMS cfg;
4907 LANPage0_t *ppage0_alloc;
4908 dma_addr_t page0_dma;
4909 LANPage1_t *ppage1_alloc;
4910 dma_addr_t page1_dma;
4911 int rc = 0;
4912 int data_sz;
4913 int copy_sz;
4914
4915 /* Get LAN Page 0 header */
4916 hdr.PageVersion = 0;
4917 hdr.PageLength = 0;
4918 hdr.PageNumber = 0;
4919 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004920 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004921 cfg.physAddr = -1;
4922 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4923 cfg.dir = 0;
4924 cfg.pageAddr = 0;
4925 cfg.timeout = 0;
4926
4927 if ((rc = mpt_config(ioc, &cfg)) != 0)
4928 return rc;
4929
4930 if (hdr.PageLength > 0) {
4931 data_sz = hdr.PageLength * 4;
4932 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4933 rc = -ENOMEM;
4934 if (ppage0_alloc) {
4935 memset((u8 *)ppage0_alloc, 0, data_sz);
4936 cfg.physAddr = page0_dma;
4937 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4938
4939 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4940 /* save the data */
4941 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4942 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4943
4944 }
4945
4946 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4947
4948 /* FIXME!
4949 * Normalize endianness of structure data,
4950 * by byte-swapping all > 1 byte fields!
4951 */
4952
4953 }
4954
4955 if (rc)
4956 return rc;
4957 }
4958
4959 /* Get LAN Page 1 header */
4960 hdr.PageVersion = 0;
4961 hdr.PageLength = 0;
4962 hdr.PageNumber = 1;
4963 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004964 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965 cfg.physAddr = -1;
4966 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4967 cfg.dir = 0;
4968 cfg.pageAddr = 0;
4969
4970 if ((rc = mpt_config(ioc, &cfg)) != 0)
4971 return rc;
4972
4973 if (hdr.PageLength == 0)
4974 return 0;
4975
4976 data_sz = hdr.PageLength * 4;
4977 rc = -ENOMEM;
4978 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4979 if (ppage1_alloc) {
4980 memset((u8 *)ppage1_alloc, 0, data_sz);
4981 cfg.physAddr = page1_dma;
4982 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4983
4984 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4985 /* save the data */
4986 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4987 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4988 }
4989
4990 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4991
4992 /* FIXME!
4993 * Normalize endianness of structure data,
4994 * by byte-swapping all > 1 byte fields!
4995 */
4996
4997 }
4998
4999 return rc;
5000}
5001
5002/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005003/**
5004 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005005 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005006 * @persist_opcode: see below
5007 *
5008 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
5009 * devices not currently present.
5010 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
5011 *
5012 * NOTE: Don't use not this function during interrupt time.
5013 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005014 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005015 */
5016
5017/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5018int
5019mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
5020{
5021 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
5022 SasIoUnitControlReply_t *sasIoUnitCntrReply;
5023 MPT_FRAME_HDR *mf = NULL;
5024 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305025 int ret = 0;
5026 unsigned long timeleft;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005027
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305028 mutex_lock(&ioc->mptbase_cmds.mutex);
5029
5030 /* init the internal cmd struct */
5031 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
5032 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005033
5034 /* insure garbage is not sent to fw */
5035 switch(persist_opcode) {
5036
5037 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
5038 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
5039 break;
5040
5041 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305042 ret = -1;
5043 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005044 }
5045
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305046 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
5047 __func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005048
5049 /* Get a MF for this command.
5050 */
5051 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305052 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
5053 ret = -1;
5054 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005055 }
5056
5057 mpi_hdr = (MPIHeader_t *) mf;
5058 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
5059 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
5060 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
5061 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
5062 sasIoUnitCntrReq->Operation = persist_opcode;
5063
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005064 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305065 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
5066 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
5067 ret = -ETIME;
5068 printk(KERN_DEBUG "%s: failed\n", __func__);
5069 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
5070 goto out;
5071 if (!timeleft) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09005072 printk(MYIOC_s_WARN_FMT
5073 "Issuing Reset from %s!!, doorbell=0x%08x\n",
5074 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05305075 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305076 mpt_free_msg_frame(ioc, mf);
5077 }
5078 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005079 }
5080
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305081 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
5082 ret = -1;
5083 goto out;
5084 }
5085
5086 sasIoUnitCntrReply =
5087 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5088 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5089 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5090 __func__, sasIoUnitCntrReply->IOCStatus,
5091 sasIoUnitCntrReply->IOCLogInfo);
5092 printk(KERN_DEBUG "%s: failed\n", __func__);
5093 ret = -1;
5094 } else
5095 printk(KERN_DEBUG "%s: success\n", __func__);
5096 out:
5097
5098 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5099 mutex_unlock(&ioc->mptbase_cmds.mutex);
5100 return ret;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005101}
5102
5103/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005104
5105static void
5106mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5107 MpiEventDataRaid_t * pRaidEventData)
5108{
5109 int volume;
5110 int reason;
5111 int disk;
5112 int status;
5113 int flags;
5114 int state;
5115
5116 volume = pRaidEventData->VolumeID;
5117 reason = pRaidEventData->ReasonCode;
5118 disk = pRaidEventData->PhysDiskNum;
5119 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5120 flags = (status >> 0) & 0xff;
5121 state = (status >> 8) & 0xff;
5122
5123 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5124 return;
5125 }
5126
5127 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5128 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5129 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005130 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5131 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005132 } else {
5133 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5134 ioc->name, volume);
5135 }
5136
5137 switch(reason) {
5138 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5139 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5140 ioc->name);
5141 break;
5142
5143 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5144
5145 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5146 ioc->name);
5147 break;
5148
5149 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5150 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5151 ioc->name);
5152 break;
5153
5154 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5155 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5156 ioc->name,
5157 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5158 ? "optimal"
5159 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5160 ? "degraded"
5161 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5162 ? "failed"
5163 : "state unknown",
5164 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5165 ? ", enabled" : "",
5166 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5167 ? ", quiesced" : "",
5168 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5169 ? ", resync in progress" : "" );
5170 break;
5171
5172 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5173 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5174 ioc->name, disk);
5175 break;
5176
5177 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5178 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5179 ioc->name);
5180 break;
5181
5182 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5183 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5184 ioc->name);
5185 break;
5186
5187 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5188 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5189 ioc->name);
5190 break;
5191
5192 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5193 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5194 ioc->name,
5195 state == MPI_PHYSDISK0_STATUS_ONLINE
5196 ? "online"
5197 : state == MPI_PHYSDISK0_STATUS_MISSING
5198 ? "missing"
5199 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5200 ? "not compatible"
5201 : state == MPI_PHYSDISK0_STATUS_FAILED
5202 ? "failed"
5203 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5204 ? "initializing"
5205 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5206 ? "offline requested"
5207 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5208 ? "failed requested"
5209 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5210 ? "offline"
5211 : "state unknown",
5212 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5213 ? ", out of sync" : "",
5214 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5215 ? ", quiesced" : "" );
5216 break;
5217
5218 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5219 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5220 ioc->name, disk);
5221 break;
5222
5223 case MPI_EVENT_RAID_RC_SMART_DATA:
5224 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5225 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5226 break;
5227
5228 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5229 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5230 ioc->name, disk);
5231 break;
5232 }
5233}
5234
5235/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005236/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5238 * @ioc: Pointer to MPT_ADAPTER structure
5239 *
5240 * Returns: 0 for success
5241 * -ENOMEM if no memory available
5242 * -EPERM if not allowed due to ISR context
5243 * -EAGAIN if no msg frames currently available
5244 * -EFAULT for non-successful reply or no reply (timeout)
5245 */
5246static int
5247GetIoUnitPage2(MPT_ADAPTER *ioc)
5248{
5249 ConfigPageHeader_t hdr;
5250 CONFIGPARMS cfg;
5251 IOUnitPage2_t *ppage_alloc;
5252 dma_addr_t page_dma;
5253 int data_sz;
5254 int rc;
5255
5256 /* Get the page header */
5257 hdr.PageVersion = 0;
5258 hdr.PageLength = 0;
5259 hdr.PageNumber = 2;
5260 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005261 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005262 cfg.physAddr = -1;
5263 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5264 cfg.dir = 0;
5265 cfg.pageAddr = 0;
5266 cfg.timeout = 0;
5267
5268 if ((rc = mpt_config(ioc, &cfg)) != 0)
5269 return rc;
5270
5271 if (hdr.PageLength == 0)
5272 return 0;
5273
5274 /* Read the config page */
5275 data_sz = hdr.PageLength * 4;
5276 rc = -ENOMEM;
5277 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5278 if (ppage_alloc) {
5279 memset((u8 *)ppage_alloc, 0, data_sz);
5280 cfg.physAddr = page_dma;
5281 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5282
5283 /* If Good, save data */
5284 if ((rc = mpt_config(ioc, &cfg)) == 0)
5285 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5286
5287 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5288 }
5289
5290 return rc;
5291}
5292
5293/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005294/**
5295 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296 * @ioc: Pointer to a Adapter Strucutre
5297 * @portnum: IOC port number
5298 *
5299 * Return: -EFAULT if read of config page header fails
5300 * or if no nvram
5301 * If read of SCSI Port Page 0 fails,
5302 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5303 * Adapter settings: async, narrow
5304 * Return 1
5305 * If read of SCSI Port Page 2 fails,
5306 * Adapter settings valid
5307 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5308 * Return 1
5309 * Else
5310 * Both valid
5311 * Return 0
5312 * CHECK - what type of locking mechanisms should be used????
5313 */
5314static int
5315mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5316{
5317 u8 *pbuf;
5318 dma_addr_t buf_dma;
5319 CONFIGPARMS cfg;
5320 ConfigPageHeader_t header;
5321 int ii;
5322 int data, rc = 0;
5323
5324 /* Allocate memory
5325 */
5326 if (!ioc->spi_data.nvram) {
5327 int sz;
5328 u8 *mem;
5329 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5330 mem = kmalloc(sz, GFP_ATOMIC);
5331 if (mem == NULL)
5332 return -EFAULT;
5333
5334 ioc->spi_data.nvram = (int *) mem;
5335
Prakash, Sathya436ace72007-07-24 15:42:08 +05305336 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005337 ioc->name, ioc->spi_data.nvram, sz));
5338 }
5339
5340 /* Invalidate NVRAM information
5341 */
5342 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5343 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5344 }
5345
5346 /* Read SPP0 header, allocate memory, then read page.
5347 */
5348 header.PageVersion = 0;
5349 header.PageLength = 0;
5350 header.PageNumber = 0;
5351 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005352 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005353 cfg.physAddr = -1;
5354 cfg.pageAddr = portnum;
5355 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5356 cfg.dir = 0;
5357 cfg.timeout = 0; /* use default */
5358 if (mpt_config(ioc, &cfg) != 0)
5359 return -EFAULT;
5360
5361 if (header.PageLength > 0) {
5362 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5363 if (pbuf) {
5364 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5365 cfg.physAddr = buf_dma;
5366 if (mpt_config(ioc, &cfg) != 0) {
5367 ioc->spi_data.maxBusWidth = MPT_NARROW;
5368 ioc->spi_data.maxSyncOffset = 0;
5369 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5370 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5371 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305372 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5373 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005374 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375 } else {
5376 /* Save the Port Page 0 data
5377 */
5378 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5379 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5380 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5381
5382 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5383 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005384 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5385 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 ioc->name, pPP0->Capabilities));
5387 }
5388 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5389 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5390 if (data) {
5391 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5392 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5393 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305394 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5395 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005396 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397 } else {
5398 ioc->spi_data.maxSyncOffset = 0;
5399 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5400 }
5401
5402 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5403
5404 /* Update the minSyncFactor based on bus type.
5405 */
5406 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5407 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5408
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005409 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305411 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5412 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005413 ioc->name, ioc->spi_data.minSyncFactor));
5414 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415 }
5416 }
5417 if (pbuf) {
5418 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5419 }
5420 }
5421 }
5422
5423 /* SCSI Port Page 2 - Read the header then the page.
5424 */
5425 header.PageVersion = 0;
5426 header.PageLength = 0;
5427 header.PageNumber = 2;
5428 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005429 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005430 cfg.physAddr = -1;
5431 cfg.pageAddr = portnum;
5432 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5433 cfg.dir = 0;
5434 if (mpt_config(ioc, &cfg) != 0)
5435 return -EFAULT;
5436
5437 if (header.PageLength > 0) {
5438 /* Allocate memory and read SCSI Port Page 2
5439 */
5440 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5441 if (pbuf) {
5442 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5443 cfg.physAddr = buf_dma;
5444 if (mpt_config(ioc, &cfg) != 0) {
5445 /* Nvram data is left with INVALID mark
5446 */
5447 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005448 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5449
5450 /* This is an ATTO adapter, read Page2 accordingly
5451 */
5452 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5453 ATTODeviceInfo_t *pdevice = NULL;
5454 u16 ATTOFlags;
5455
5456 /* Save the Port Page 2 data
5457 * (reformat into a 32bit quantity)
5458 */
5459 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5460 pdevice = &pPP2->DeviceSettings[ii];
5461 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5462 data = 0;
5463
5464 /* Translate ATTO device flags to LSI format
5465 */
5466 if (ATTOFlags & ATTOFLAG_DISC)
5467 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5468 if (ATTOFlags & ATTOFLAG_ID_ENB)
5469 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5470 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5471 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5472 if (ATTOFlags & ATTOFLAG_TAGGED)
5473 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5474 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5475 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5476
5477 data = (data << 16) | (pdevice->Period << 8) | 10;
5478 ioc->spi_data.nvram[ii] = data;
5479 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480 } else {
5481 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5482 MpiDeviceInfo_t *pdevice = NULL;
5483
Moore, Ericd8e925d2006-01-16 18:53:06 -07005484 /*
5485 * Save "Set to Avoid SCSI Bus Resets" flag
5486 */
5487 ioc->spi_data.bus_reset =
5488 (le32_to_cpu(pPP2->PortFlags) &
5489 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5490 0 : 1 ;
5491
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492 /* Save the Port Page 2 data
5493 * (reformat into a 32bit quantity)
5494 */
5495 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5496 ioc->spi_data.PortFlags = data;
5497 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5498 pdevice = &pPP2->DeviceSettings[ii];
5499 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5500 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5501 ioc->spi_data.nvram[ii] = data;
5502 }
5503 }
5504
5505 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5506 }
5507 }
5508
5509 /* Update Adapter limits with those from NVRAM
5510 * Comment: Don't need to do this. Target performance
5511 * parameters will never exceed the adapters limits.
5512 */
5513
5514 return rc;
5515}
5516
5517/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005518/**
5519 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520 * @ioc: Pointer to a Adapter Strucutre
5521 * @portnum: IOC port number
5522 *
5523 * Return: -EFAULT if read of config page header fails
5524 * or 0 if success.
5525 */
5526static int
5527mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5528{
5529 CONFIGPARMS cfg;
5530 ConfigPageHeader_t header;
5531
5532 /* Read the SCSI Device Page 1 header
5533 */
5534 header.PageVersion = 0;
5535 header.PageLength = 0;
5536 header.PageNumber = 1;
5537 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005538 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539 cfg.physAddr = -1;
5540 cfg.pageAddr = portnum;
5541 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5542 cfg.dir = 0;
5543 cfg.timeout = 0;
5544 if (mpt_config(ioc, &cfg) != 0)
5545 return -EFAULT;
5546
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005547 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5548 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549
5550 header.PageVersion = 0;
5551 header.PageLength = 0;
5552 header.PageNumber = 0;
5553 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5554 if (mpt_config(ioc, &cfg) != 0)
5555 return -EFAULT;
5556
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005557 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5558 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559
Prakash, Sathya436ace72007-07-24 15:42:08 +05305560 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5562
Prakash, Sathya436ace72007-07-24 15:42:08 +05305563 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005564 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5565 return 0;
5566}
5567
Eric Mooreb506ade2007-01-29 09:45:37 -07005568/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005569 * mpt_inactive_raid_list_free - This clears this link list.
5570 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005571 **/
5572static void
5573mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5574{
5575 struct inactive_raid_component_info *component_info, *pNext;
5576
5577 if (list_empty(&ioc->raid_data.inactive_list))
5578 return;
5579
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005580 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005581 list_for_each_entry_safe(component_info, pNext,
5582 &ioc->raid_data.inactive_list, list) {
5583 list_del(&component_info->list);
5584 kfree(component_info);
5585 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005586 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005587}
5588
5589/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005590 * 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 -07005591 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005592 * @ioc : pointer to per adapter structure
5593 * @channel : volume channel
5594 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005595 **/
5596static void
5597mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5598{
5599 CONFIGPARMS cfg;
5600 ConfigPageHeader_t hdr;
5601 dma_addr_t dma_handle;
5602 pRaidVolumePage0_t buffer = NULL;
5603 int i;
5604 RaidPhysDiskPage0_t phys_disk;
5605 struct inactive_raid_component_info *component_info;
5606 int handle_inactive_volumes;
5607
5608 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5609 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5610 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5611 cfg.pageAddr = (channel << 8) + id;
5612 cfg.cfghdr.hdr = &hdr;
5613 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5614
5615 if (mpt_config(ioc, &cfg) != 0)
5616 goto out;
5617
5618 if (!hdr.PageLength)
5619 goto out;
5620
5621 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5622 &dma_handle);
5623
5624 if (!buffer)
5625 goto out;
5626
5627 cfg.physAddr = dma_handle;
5628 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5629
5630 if (mpt_config(ioc, &cfg) != 0)
5631 goto out;
5632
5633 if (!buffer->NumPhysDisks)
5634 goto out;
5635
5636 handle_inactive_volumes =
5637 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5638 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5639 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5640 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5641
5642 if (!handle_inactive_volumes)
5643 goto out;
5644
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005645 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005646 for (i = 0; i < buffer->NumPhysDisks; i++) {
5647 if(mpt_raid_phys_disk_pg0(ioc,
5648 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5649 continue;
5650
5651 if ((component_info = kmalloc(sizeof (*component_info),
5652 GFP_KERNEL)) == NULL)
5653 continue;
5654
5655 component_info->volumeID = id;
5656 component_info->volumeBus = channel;
5657 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5658 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5659 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5660 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5661
5662 list_add_tail(&component_info->list,
5663 &ioc->raid_data.inactive_list);
5664 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005665 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005666
5667 out:
5668 if (buffer)
5669 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5670 dma_handle);
5671}
5672
5673/**
5674 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5675 * @ioc: Pointer to a Adapter Structure
5676 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5677 * @phys_disk: requested payload data returned
5678 *
5679 * Return:
5680 * 0 on success
5681 * -EFAULT if read of config page header fails or data pointer not NULL
5682 * -ENOMEM if pci_alloc failed
5683 **/
5684int
Kashyap, Desai2f187862009-05-29 16:52:37 +05305685mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
5686 RaidPhysDiskPage0_t *phys_disk)
Eric Mooreb506ade2007-01-29 09:45:37 -07005687{
Kashyap, Desai2f187862009-05-29 16:52:37 +05305688 CONFIGPARMS cfg;
5689 ConfigPageHeader_t hdr;
Eric Mooreb506ade2007-01-29 09:45:37 -07005690 dma_addr_t dma_handle;
5691 pRaidPhysDiskPage0_t buffer = NULL;
5692 int rc;
5693
5694 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5695 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
Kashyap, Desai2f187862009-05-29 16:52:37 +05305696 memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
Eric Mooreb506ade2007-01-29 09:45:37 -07005697
Kashyap, Desai2f187862009-05-29 16:52:37 +05305698 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
Eric Mooreb506ade2007-01-29 09:45:37 -07005699 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5700 cfg.cfghdr.hdr = &hdr;
5701 cfg.physAddr = -1;
5702 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5703
5704 if (mpt_config(ioc, &cfg) != 0) {
5705 rc = -EFAULT;
5706 goto out;
5707 }
5708
5709 if (!hdr.PageLength) {
5710 rc = -EFAULT;
5711 goto out;
5712 }
5713
5714 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5715 &dma_handle);
5716
5717 if (!buffer) {
5718 rc = -ENOMEM;
5719 goto out;
5720 }
5721
5722 cfg.physAddr = dma_handle;
5723 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5724 cfg.pageAddr = phys_disk_num;
5725
5726 if (mpt_config(ioc, &cfg) != 0) {
5727 rc = -EFAULT;
5728 goto out;
5729 }
5730
5731 rc = 0;
5732 memcpy(phys_disk, buffer, sizeof(*buffer));
5733 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5734
5735 out:
5736
5737 if (buffer)
5738 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5739 dma_handle);
5740
5741 return rc;
5742}
5743
Linus Torvalds1da177e2005-04-16 15:20:36 -07005744/**
Kashyap, Desaia7938b02009-05-29 16:53:56 +05305745 * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
5746 * @ioc: Pointer to a Adapter Structure
5747 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5748 *
5749 * Return:
5750 * returns number paths
5751 **/
5752int
5753mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
5754{
5755 CONFIGPARMS cfg;
5756 ConfigPageHeader_t hdr;
5757 dma_addr_t dma_handle;
5758 pRaidPhysDiskPage1_t buffer = NULL;
5759 int rc;
5760
5761 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5762 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5763
5764 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5765 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5766 hdr.PageNumber = 1;
5767 cfg.cfghdr.hdr = &hdr;
5768 cfg.physAddr = -1;
5769 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5770
5771 if (mpt_config(ioc, &cfg) != 0) {
5772 rc = 0;
5773 goto out;
5774 }
5775
5776 if (!hdr.PageLength) {
5777 rc = 0;
5778 goto out;
5779 }
5780
5781 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5782 &dma_handle);
5783
5784 if (!buffer) {
5785 rc = 0;
5786 goto out;
5787 }
5788
5789 cfg.physAddr = dma_handle;
5790 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5791 cfg.pageAddr = phys_disk_num;
5792
5793 if (mpt_config(ioc, &cfg) != 0) {
5794 rc = 0;
5795 goto out;
5796 }
5797
5798 rc = buffer->NumPhysDiskPaths;
5799 out:
5800
5801 if (buffer)
5802 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5803 dma_handle);
5804
5805 return rc;
5806}
5807EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
5808
5809/**
5810 * mpt_raid_phys_disk_pg1 - returns phys disk page 1
5811 * @ioc: Pointer to a Adapter Structure
5812 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5813 * @phys_disk: requested payload data returned
5814 *
5815 * Return:
5816 * 0 on success
5817 * -EFAULT if read of config page header fails or data pointer not NULL
5818 * -ENOMEM if pci_alloc failed
5819 **/
5820int
5821mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
5822 RaidPhysDiskPage1_t *phys_disk)
5823{
5824 CONFIGPARMS cfg;
5825 ConfigPageHeader_t hdr;
5826 dma_addr_t dma_handle;
5827 pRaidPhysDiskPage1_t buffer = NULL;
5828 int rc;
5829 int i;
5830 __le64 sas_address;
5831
5832 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5833 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5834 rc = 0;
5835
5836 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5837 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5838 hdr.PageNumber = 1;
5839 cfg.cfghdr.hdr = &hdr;
5840 cfg.physAddr = -1;
5841 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5842
5843 if (mpt_config(ioc, &cfg) != 0) {
5844 rc = -EFAULT;
5845 goto out;
5846 }
5847
5848 if (!hdr.PageLength) {
5849 rc = -EFAULT;
5850 goto out;
5851 }
5852
5853 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5854 &dma_handle);
5855
5856 if (!buffer) {
5857 rc = -ENOMEM;
5858 goto out;
5859 }
5860
5861 cfg.physAddr = dma_handle;
5862 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5863 cfg.pageAddr = phys_disk_num;
5864
5865 if (mpt_config(ioc, &cfg) != 0) {
5866 rc = -EFAULT;
5867 goto out;
5868 }
5869
5870 phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
5871 phys_disk->PhysDiskNum = phys_disk_num;
5872 for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
5873 phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
5874 phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
5875 phys_disk->Path[i].OwnerIdentifier =
5876 buffer->Path[i].OwnerIdentifier;
5877 phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
5878 memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
5879 sas_address = le64_to_cpu(sas_address);
5880 memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
5881 memcpy(&sas_address,
5882 &buffer->Path[i].OwnerWWID, sizeof(__le64));
5883 sas_address = le64_to_cpu(sas_address);
5884 memcpy(&phys_disk->Path[i].OwnerWWID,
5885 &sas_address, sizeof(__le64));
5886 }
5887
5888 out:
5889
5890 if (buffer)
5891 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5892 dma_handle);
5893
5894 return rc;
5895}
5896EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
5897
5898
5899/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005900 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5901 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902 *
5903 * Return:
5904 * 0 on success
5905 * -EFAULT if read of config page header fails or data pointer not NULL
5906 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005907 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908int
5909mpt_findImVolumes(MPT_ADAPTER *ioc)
5910{
5911 IOCPage2_t *pIoc2;
5912 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005913 dma_addr_t ioc2_dma;
5914 CONFIGPARMS cfg;
5915 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005916 int rc = 0;
5917 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005918 int i;
5919
5920 if (!ioc->ir_firmware)
5921 return 0;
5922
5923 /* Free the old page
5924 */
5925 kfree(ioc->raid_data.pIocPg2);
5926 ioc->raid_data.pIocPg2 = NULL;
5927 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005928
5929 /* Read IOCP2 header then the page.
5930 */
5931 header.PageVersion = 0;
5932 header.PageLength = 0;
5933 header.PageNumber = 2;
5934 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005935 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005936 cfg.physAddr = -1;
5937 cfg.pageAddr = 0;
5938 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5939 cfg.dir = 0;
5940 cfg.timeout = 0;
5941 if (mpt_config(ioc, &cfg) != 0)
5942 return -EFAULT;
5943
5944 if (header.PageLength == 0)
5945 return -EFAULT;
5946
5947 iocpage2sz = header.PageLength * 4;
5948 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5949 if (!pIoc2)
5950 return -ENOMEM;
5951
5952 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5953 cfg.physAddr = ioc2_dma;
5954 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005955 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005956
Eric Mooreb506ade2007-01-29 09:45:37 -07005957 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5958 if (!mem)
5959 goto out;
5960
Linus Torvalds1da177e2005-04-16 15:20:36 -07005961 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005962 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963
Eric Mooreb506ade2007-01-29 09:45:37 -07005964 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005965
Eric Mooreb506ade2007-01-29 09:45:37 -07005966 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5967 mpt_inactive_raid_volumes(ioc,
5968 pIoc2->RaidVolume[i].VolumeBus,
5969 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970
Eric Mooreb506ade2007-01-29 09:45:37 -07005971 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005972 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5973
5974 return rc;
5975}
5976
Moore, Ericc972c702006-03-14 09:14:06 -07005977static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005978mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5979{
5980 IOCPage3_t *pIoc3;
5981 u8 *mem;
5982 CONFIGPARMS cfg;
5983 ConfigPageHeader_t header;
5984 dma_addr_t ioc3_dma;
5985 int iocpage3sz = 0;
5986
5987 /* Free the old page
5988 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005989 kfree(ioc->raid_data.pIocPg3);
5990 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005991
5992 /* There is at least one physical disk.
5993 * Read and save IOC Page 3
5994 */
5995 header.PageVersion = 0;
5996 header.PageLength = 0;
5997 header.PageNumber = 3;
5998 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005999 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006000 cfg.physAddr = -1;
6001 cfg.pageAddr = 0;
6002 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6003 cfg.dir = 0;
6004 cfg.timeout = 0;
6005 if (mpt_config(ioc, &cfg) != 0)
6006 return 0;
6007
6008 if (header.PageLength == 0)
6009 return 0;
6010
6011 /* Read Header good, alloc memory
6012 */
6013 iocpage3sz = header.PageLength * 4;
6014 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
6015 if (!pIoc3)
6016 return 0;
6017
6018 /* Read the Page and save the data
6019 * into malloc'd memory.
6020 */
6021 cfg.physAddr = ioc3_dma;
6022 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6023 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07006024 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006025 if (mem) {
6026 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006027 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006028 }
6029 }
6030
6031 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
6032
6033 return 0;
6034}
6035
6036static void
6037mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
6038{
6039 IOCPage4_t *pIoc4;
6040 CONFIGPARMS cfg;
6041 ConfigPageHeader_t header;
6042 dma_addr_t ioc4_dma;
6043 int iocpage4sz;
6044
6045 /* Read and save IOC Page 4
6046 */
6047 header.PageVersion = 0;
6048 header.PageLength = 0;
6049 header.PageNumber = 4;
6050 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006051 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006052 cfg.physAddr = -1;
6053 cfg.pageAddr = 0;
6054 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6055 cfg.dir = 0;
6056 cfg.timeout = 0;
6057 if (mpt_config(ioc, &cfg) != 0)
6058 return;
6059
6060 if (header.PageLength == 0)
6061 return;
6062
6063 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
6064 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
6065 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
6066 if (!pIoc4)
6067 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06006068 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006069 } else {
6070 ioc4_dma = ioc->spi_data.IocPg4_dma;
6071 iocpage4sz = ioc->spi_data.IocPg4Sz;
6072 }
6073
6074 /* Read the Page into dma memory.
6075 */
6076 cfg.physAddr = ioc4_dma;
6077 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6078 if (mpt_config(ioc, &cfg) == 0) {
6079 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
6080 ioc->spi_data.IocPg4_dma = ioc4_dma;
6081 ioc->spi_data.IocPg4Sz = iocpage4sz;
6082 } else {
6083 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
6084 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06006085 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006086 }
6087}
6088
6089static void
6090mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
6091{
6092 IOCPage1_t *pIoc1;
6093 CONFIGPARMS cfg;
6094 ConfigPageHeader_t header;
6095 dma_addr_t ioc1_dma;
6096 int iocpage1sz = 0;
6097 u32 tmp;
6098
6099 /* Check the Coalescing Timeout in IOC Page 1
6100 */
6101 header.PageVersion = 0;
6102 header.PageLength = 0;
6103 header.PageNumber = 1;
6104 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006105 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006106 cfg.physAddr = -1;
6107 cfg.pageAddr = 0;
6108 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6109 cfg.dir = 0;
6110 cfg.timeout = 0;
6111 if (mpt_config(ioc, &cfg) != 0)
6112 return;
6113
6114 if (header.PageLength == 0)
6115 return;
6116
6117 /* Read Header good, alloc memory
6118 */
6119 iocpage1sz = header.PageLength * 4;
6120 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
6121 if (!pIoc1)
6122 return;
6123
6124 /* Read the Page and check coalescing timeout
6125 */
6126 cfg.physAddr = ioc1_dma;
6127 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6128 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306129
Linus Torvalds1da177e2005-04-16 15:20:36 -07006130 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
6131 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
6132 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
6133
Prakash, Sathya436ace72007-07-24 15:42:08 +05306134 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135 ioc->name, tmp));
6136
6137 if (tmp > MPT_COALESCING_TIMEOUT) {
6138 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
6139
6140 /* Write NVRAM and current
6141 */
6142 cfg.dir = 1;
6143 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
6144 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306145 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006146 ioc->name, MPT_COALESCING_TIMEOUT));
6147
6148 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
6149 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306150 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6151 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006152 ioc->name, MPT_COALESCING_TIMEOUT));
6153 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306154 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6155 "Reset NVRAM Coalescing Timeout Failed\n",
6156 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006157 }
6158
6159 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306160 dprintk(ioc, printk(MYIOC_s_WARN_FMT
6161 "Reset of Current Coalescing Timeout Failed!\n",
6162 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006163 }
6164 }
6165
6166 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306167 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006168 }
6169 }
6170
6171 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
6172
6173 return;
6174}
6175
Prakash, Sathyaedb90682007-07-17 14:39:14 +05306176static void
6177mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
6178{
6179 CONFIGPARMS cfg;
6180 ConfigPageHeader_t hdr;
6181 dma_addr_t buf_dma;
6182 ManufacturingPage0_t *pbuf = NULL;
6183
6184 memset(&cfg, 0 , sizeof(CONFIGPARMS));
6185 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
6186
6187 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
6188 cfg.cfghdr.hdr = &hdr;
6189 cfg.physAddr = -1;
6190 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6191 cfg.timeout = 10;
6192
6193 if (mpt_config(ioc, &cfg) != 0)
6194 goto out;
6195
6196 if (!cfg.cfghdr.hdr->PageLength)
6197 goto out;
6198
6199 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6200 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
6201 if (!pbuf)
6202 goto out;
6203
6204 cfg.physAddr = buf_dma;
6205
6206 if (mpt_config(ioc, &cfg) != 0)
6207 goto out;
6208
6209 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
6210 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
6211 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
6212
6213 out:
6214
6215 if (pbuf)
6216 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
6217}
6218
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006220/**
6221 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006222 * @ioc: Pointer to MPT_ADAPTER structure
6223 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05306224 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07006225 */
6226static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05306227SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228{
Kashyap, Desaifd761752009-05-29 16:39:06 +05306229 EventNotification_t evn;
6230 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006231
Kashyap, Desaifd761752009-05-29 16:39:06 +05306232 memset(&evn, 0, sizeof(EventNotification_t));
6233 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006234
Kashyap, Desaifd761752009-05-29 16:39:06 +05306235 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
6236 evn.Switch = EvSwitch;
6237 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006238
Kashyap, Desaifd761752009-05-29 16:39:06 +05306239 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6240 "Sending EventNotification (%d) request %p\n",
6241 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006242
Kashyap, Desaifd761752009-05-29 16:39:06 +05306243 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6244 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6245 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006246}
6247
6248/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6249/**
6250 * SendEventAck - Send EventAck request to MPT adapter.
6251 * @ioc: Pointer to MPT_ADAPTER structure
6252 * @evnp: Pointer to original EventNotification request
6253 */
6254static int
6255SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6256{
6257 EventAck_t *pAck;
6258
6259 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306260 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306261 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006262 return -1;
6263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264
Prakash, Sathya436ace72007-07-24 15:42:08 +05306265 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006266
6267 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6268 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006269 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006270 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006271 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006272 pAck->Event = evnp->Event;
6273 pAck->EventContext = evnp->EventContext;
6274
6275 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6276
6277 return 0;
6278}
6279
6280/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6281/**
6282 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006283 * @ioc: Pointer to an adapter structure
6284 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006285 * action, page address, direction, physical address
6286 * and pointer to a configuration page header
6287 * Page header is updated.
6288 *
6289 * Returns 0 for success
6290 * -EPERM if not allowed due to ISR context
6291 * -EAGAIN if no msg frames currently available
6292 * -EFAULT for non-successful reply or no reply (timeout)
6293 */
6294int
6295mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6296{
6297 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306298 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006299 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006300 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306301 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006302 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306303 long timeout;
6304 int ret;
6305 u8 page_type = 0, extend_page;
6306 unsigned long timeleft;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306307 unsigned long flags;
6308 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306309 u8 issue_hard_reset = 0;
6310 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006311
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006312 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006313 * to be in ISR context, because that is fatal!
6314 */
6315 in_isr = in_interrupt();
6316 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306317 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006318 ioc->name));
6319 return -EPERM;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306320 }
6321
6322 /* don't send a config page during diag reset */
6323 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6324 if (ioc->ioc_reset_in_progress) {
6325 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6326 "%s: busy with host reset\n", ioc->name, __func__));
6327 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6328 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006329 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306330 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006331
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306332 /* don't send if no chance of success */
6333 if (!ioc->active ||
6334 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6335 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6336 "%s: ioc not operational, %d, %xh\n",
6337 ioc->name, __func__, ioc->active,
6338 mpt_GetIocState(ioc, 0)));
6339 return -EFAULT;
6340 }
6341
6342 retry_config:
6343 mutex_lock(&ioc->mptbase_cmds.mutex);
6344 /* init the internal cmd struct */
6345 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6346 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6347
Linus Torvalds1da177e2005-04-16 15:20:36 -07006348 /* Get and Populate a free Frame
6349 */
6350 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306351 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6352 "mpt_config: no msg frames!\n", ioc->name));
6353 ret = -EAGAIN;
6354 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006355 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306356
Linus Torvalds1da177e2005-04-16 15:20:36 -07006357 pReq = (Config_t *)mf;
6358 pReq->Action = pCfg->action;
6359 pReq->Reserved = 0;
6360 pReq->ChainOffset = 0;
6361 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006362
6363 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006364 pReq->ExtPageLength = 0;
6365 pReq->ExtPageType = 0;
6366 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006367
Linus Torvalds1da177e2005-04-16 15:20:36 -07006368 for (ii=0; ii < 8; ii++)
6369 pReq->Reserved2[ii] = 0;
6370
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006371 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6372 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6373 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6374 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6375
6376 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6377 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6378 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6379 pReq->ExtPageType = pExtHdr->ExtPageType;
6380 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6381
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306382 /* Page Length must be treated as a reserved field for the
6383 * extended header.
6384 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006385 pReq->Header.PageLength = 0;
6386 }
6387
Linus Torvalds1da177e2005-04-16 15:20:36 -07006388 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6389
6390 /* Add a SGE to the config request.
6391 */
6392 if (pCfg->dir)
6393 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6394 else
6395 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6396
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306397 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6398 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006399 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306400 page_type = pReq->ExtPageType;
6401 extend_page = 1;
6402 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006403 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306404 page_type = pReq->Header.PageType;
6405 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006407
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306408 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6409 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6410 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6411
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306412 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306413 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006414 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306415 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6416 timeout);
6417 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6418 ret = -ETIME;
6419 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6420 "Failed Sending Config request type 0x%x, page 0x%x,"
6421 " action %d, status %xh, time left %ld\n\n",
6422 ioc->name, page_type, pReq->Header.PageNumber,
6423 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6424 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6425 goto out;
6426 if (!timeleft)
6427 issue_hard_reset = 1;
6428 goto out;
6429 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006430
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306431 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6432 ret = -1;
6433 goto out;
6434 }
6435 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6436 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6437 if (ret == MPI_IOCSTATUS_SUCCESS) {
6438 if (extend_page) {
6439 pCfg->cfghdr.ehdr->ExtPageLength =
6440 le16_to_cpu(pReply->ExtPageLength);
6441 pCfg->cfghdr.ehdr->ExtPageType =
6442 pReply->ExtPageType;
6443 }
6444 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6445 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6446 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6447 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006448
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306449 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006450
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306451 if (retry_count)
6452 printk(MYIOC_s_INFO_FMT "Retry completed "
6453 "ret=0x%x timeleft=%ld\n",
6454 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006455
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306456 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6457 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006458
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306459out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006460
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306461 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6462 mutex_unlock(&ioc->mptbase_cmds.mutex);
6463 if (issue_hard_reset) {
6464 issue_hard_reset = 0;
Kei Tokunaga97009a22010-06-22 19:01:51 +09006465 printk(MYIOC_s_WARN_FMT
6466 "Issuing Reset from %s!!, doorbell=0x%08x\n",
6467 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaib3b97312010-03-18 19:14:51 +05306468 if (retry_count == 0) {
6469 if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0)
6470 retry_count++;
6471 } else
6472 mpt_HardResetHandler(ioc, CAN_SLEEP);
6473
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306474 mpt_free_msg_frame(ioc, mf);
6475 /* attempt one retry for a timed out command */
Kashyap, Desaib3b97312010-03-18 19:14:51 +05306476 if (retry_count < 2) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306477 printk(MYIOC_s_INFO_FMT
6478 "Attempting Retry Config request"
6479 " type 0x%x, page 0x%x,"
6480 " action %d\n", ioc->name, page_type,
6481 pCfg->cfghdr.hdr->PageNumber, pCfg->action);
6482 retry_count++;
6483 goto retry_config;
6484 }
6485 }
6486 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006487
Linus Torvalds1da177e2005-04-16 15:20:36 -07006488}
6489
6490/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006491/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006492 * mpt_ioc_reset - Base cleanup for hard reset
6493 * @ioc: Pointer to the adapter structure
6494 * @reset_phase: Indicates pre- or post-reset functionality
6495 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006496 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006497 */
6498static int
6499mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6500{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306501 switch (reset_phase) {
6502 case MPT_IOC_SETUP_RESET:
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306503 ioc->taskmgmt_quiesce_io = 1;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306504 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6505 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
6506 break;
6507 case MPT_IOC_PRE_RESET:
6508 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6509 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
6510 break;
6511 case MPT_IOC_POST_RESET:
6512 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6513 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
6514/* wake up mptbase_cmds */
6515 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6516 ioc->mptbase_cmds.status |=
6517 MPT_MGMT_STATUS_DID_IOCRESET;
6518 complete(&ioc->mptbase_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006519 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306520/* wake up taskmgmt_cmds */
6521 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
6522 ioc->taskmgmt_cmds.status |=
6523 MPT_MGMT_STATUS_DID_IOCRESET;
6524 complete(&ioc->taskmgmt_cmds.done);
6525 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306526 break;
6527 default:
6528 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006529 }
6530
6531 return 1; /* currently means nothing really */
6532}
6533
6534
6535#ifdef CONFIG_PROC_FS /* { */
6536/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6537/*
6538 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6539 */
6540/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006541/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006542 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6543 *
6544 * Returns 0 for success, non-zero for failure.
6545 */
6546static int
6547procmpt_create(void)
6548{
6549 struct proc_dir_entry *ent;
6550
6551 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6552 if (mpt_proc_root_dir == NULL)
6553 return -ENOTDIR;
6554
6555 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6556 if (ent)
6557 ent->read_proc = procmpt_summary_read;
6558
6559 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6560 if (ent)
6561 ent->read_proc = procmpt_version_read;
6562
6563 return 0;
6564}
6565
6566/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006567/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006568 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6569 *
6570 * Returns 0 for success, non-zero for failure.
6571 */
6572static void
6573procmpt_destroy(void)
6574{
6575 remove_proc_entry("version", mpt_proc_root_dir);
6576 remove_proc_entry("summary", mpt_proc_root_dir);
6577 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6578}
6579
6580/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006581/**
6582 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006583 * @buf: Pointer to area to write information
6584 * @start: Pointer to start pointer
6585 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006586 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006587 * @eof: Pointer to EOF integer
6588 * @data: Pointer
6589 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006590 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006591 * Returns number of characters written to process performing the read.
6592 */
6593static int
6594procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6595{
6596 MPT_ADAPTER *ioc;
6597 char *out = buf;
6598 int len;
6599
6600 if (data) {
6601 int more = 0;
6602
6603 ioc = data;
6604 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6605
6606 out += more;
6607 } else {
6608 list_for_each_entry(ioc, &ioc_list, list) {
6609 int more = 0;
6610
6611 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6612
6613 out += more;
6614 if ((out-buf) >= request)
6615 break;
6616 }
6617 }
6618
6619 len = out - buf;
6620
6621 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6622}
6623
6624/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006625/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006626 * procmpt_version_read - Handle read request from /proc/mpt/version.
6627 * @buf: Pointer to area to write information
6628 * @start: Pointer to start pointer
6629 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006630 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006631 * @eof: Pointer to EOF integer
6632 * @data: Pointer
6633 *
6634 * Returns number of characters written to process performing the read.
6635 */
6636static int
6637procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6638{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306639 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006640 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006641 char *drvname;
6642 int len;
6643
6644 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6645 len += sprintf(buf+len, " Fusion MPT base driver\n");
6646
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006647 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006648 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006649 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306650 if (MptCallbacks[cb_idx]) {
6651 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006652 case MPTSPI_DRIVER:
6653 if (!scsi++) drvname = "SPI host";
6654 break;
6655 case MPTFC_DRIVER:
6656 if (!fc++) drvname = "FC host";
6657 break;
6658 case MPTSAS_DRIVER:
6659 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006660 break;
6661 case MPTLAN_DRIVER:
6662 if (!lan++) drvname = "LAN";
6663 break;
6664 case MPTSTM_DRIVER:
6665 if (!targ++) drvname = "SCSI target";
6666 break;
6667 case MPTCTL_DRIVER:
6668 if (!ctl++) drvname = "ioctl";
6669 break;
6670 }
6671
6672 if (drvname)
6673 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6674 }
6675 }
6676
6677 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6678}
6679
6680/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006681/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006682 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6683 * @buf: Pointer to area to write information
6684 * @start: Pointer to start pointer
6685 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006686 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006687 * @eof: Pointer to EOF integer
6688 * @data: Pointer
6689 *
6690 * Returns number of characters written to process performing the read.
6691 */
6692static int
6693procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6694{
6695 MPT_ADAPTER *ioc = data;
6696 int len;
6697 char expVer[32];
6698 int sz;
6699 int p;
6700
6701 mpt_get_fw_exp_ver(expVer, ioc);
6702
6703 len = sprintf(buf, "%s:", ioc->name);
6704 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6705 len += sprintf(buf+len, " (f/w download boot flag set)");
6706// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6707// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6708
6709 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6710 ioc->facts.ProductID,
6711 ioc->prod_name);
6712 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6713 if (ioc->facts.FWImageSize)
6714 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6715 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6716 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6717 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6718
6719 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6720 ioc->facts.CurrentHostMfaHighAddr);
6721 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6722 ioc->facts.CurrentSenseBufferHighAddr);
6723
6724 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6725 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6726
6727 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6728 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6729 /*
6730 * Rounding UP to nearest 4-kB boundary here...
6731 */
6732 sz = (ioc->req_sz * ioc->req_depth) + 128;
6733 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6734 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6735 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6736 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6737 4*ioc->facts.RequestFrameSize,
6738 ioc->facts.GlobalCredits);
6739
6740 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6741 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6742 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6743 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6744 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6745 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6746 ioc->facts.CurReplyFrameSize,
6747 ioc->facts.ReplyQueueDepth);
6748
6749 len += sprintf(buf+len, " MaxDevices = %d\n",
6750 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6751 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6752
6753 /* per-port info */
6754 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6755 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6756 p+1,
6757 ioc->facts.NumberOfPorts);
6758 if (ioc->bus_type == FC) {
6759 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6760 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6761 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6762 a[5], a[4], a[3], a[2], a[1], a[0]);
6763 }
6764 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6765 ioc->fc_port_page0[p].WWNN.High,
6766 ioc->fc_port_page0[p].WWNN.Low,
6767 ioc->fc_port_page0[p].WWPN.High,
6768 ioc->fc_port_page0[p].WWPN.Low);
6769 }
6770 }
6771
6772 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6773}
6774
6775#endif /* CONFIG_PROC_FS } */
6776
6777/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6778static void
6779mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6780{
6781 buf[0] ='\0';
6782 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6783 sprintf(buf, " (Exp %02d%02d)",
6784 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6785 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6786
6787 /* insider hack! */
6788 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6789 strcat(buf, " [MDBG]");
6790 }
6791}
6792
6793/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6794/**
6795 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6796 * @ioc: Pointer to MPT_ADAPTER structure
6797 * @buffer: Pointer to buffer where IOC summary info should be written
6798 * @size: Pointer to number of bytes we wrote (set by this routine)
6799 * @len: Offset at which to start writing in buffer
6800 * @showlan: Display LAN stuff?
6801 *
6802 * This routine writes (english readable) ASCII text, which represents
6803 * a summary of IOC information, to a buffer.
6804 */
6805void
6806mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6807{
6808 char expVer[32];
6809 int y;
6810
6811 mpt_get_fw_exp_ver(expVer, ioc);
6812
6813 /*
6814 * Shorter summary of attached ioc's...
6815 */
6816 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6817 ioc->name,
6818 ioc->prod_name,
6819 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6820 ioc->facts.FWVersion.Word,
6821 expVer,
6822 ioc->facts.NumberOfPorts,
6823 ioc->req_depth);
6824
6825 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6826 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6827 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6828 a[5], a[4], a[3], a[2], a[1], a[0]);
6829 }
6830
Linus Torvalds1da177e2005-04-16 15:20:36 -07006831 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006832
6833 if (!ioc->active)
6834 y += sprintf(buffer+len+y, " (disabled)");
6835
6836 y += sprintf(buffer+len+y, "\n");
6837
6838 *size = y;
6839}
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306840/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006841 * mpt_set_taskmgmt_in_progress_flag - set flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306842 * @ioc: Pointer to MPT_ADAPTER structure
6843 *
6844 * Returns 0 for SUCCESS or -1 if FAILED.
6845 *
6846 * If -1 is return, then it was not possible to set the flags
6847 **/
6848int
6849mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6850{
6851 unsigned long flags;
6852 int retval;
6853
6854 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6855 if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
6856 (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
6857 retval = -1;
6858 goto out;
6859 }
6860 retval = 0;
6861 ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306862 ioc->taskmgmt_quiesce_io = 1;
6863 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306864 ioc->alt_ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306865 ioc->alt_ioc->taskmgmt_quiesce_io = 1;
6866 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306867 out:
6868 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6869 return retval;
6870}
6871EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
6872
6873/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006874 * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306875 * @ioc: Pointer to MPT_ADAPTER structure
6876 *
6877 **/
6878void
6879mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6880{
6881 unsigned long flags;
6882
6883 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6884 ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306885 ioc->taskmgmt_quiesce_io = 0;
6886 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306887 ioc->alt_ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306888 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
6889 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306890 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6891}
6892EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006893
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306894
6895/**
6896 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6897 * the kernel
6898 * @ioc: Pointer to MPT_ADAPTER structure
6899 *
6900 **/
6901void
6902mpt_halt_firmware(MPT_ADAPTER *ioc)
6903{
6904 u32 ioc_raw_state;
6905
6906 ioc_raw_state = mpt_GetIocState(ioc, 0);
6907
6908 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6909 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6910 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6911 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6912 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6913 } else {
6914 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6915 panic("%s: Firmware is halted due to command timeout\n",
6916 ioc->name);
6917 }
6918}
6919EXPORT_SYMBOL(mpt_halt_firmware);
6920
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306921/**
6922 * mpt_SoftResetHandler - Issues a less expensive reset
6923 * @ioc: Pointer to MPT_ADAPTER structure
6924 * @sleepFlag: Indicates if sleep or schedule must be called.
6925
6926 *
6927 * Returns 0 for SUCCESS or -1 if FAILED.
6928 *
6929 * Message Unit Reset - instructs the IOC to reset the Reply Post and
6930 * Free FIFO's. All the Message Frames on Reply Free FIFO are discarded.
6931 * All posted buffers are freed, and event notification is turned off.
6932 * IOC doesnt reply to any outstanding request. This will transfer IOC
6933 * to READY state.
6934 **/
6935int
6936mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6937{
6938 int rc;
6939 int ii;
6940 u8 cb_idx;
6941 unsigned long flags;
6942 u32 ioc_state;
6943 unsigned long time_count;
6944
6945 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n",
6946 ioc->name));
6947
6948 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
6949
6950 if (mpt_fwfault_debug)
6951 mpt_halt_firmware(ioc);
6952
6953 if (ioc_state == MPI_IOC_STATE_FAULT ||
6954 ioc_state == MPI_IOC_STATE_RESET) {
6955 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6956 "skipping, either in FAULT or RESET state!\n", ioc->name));
6957 return -1;
6958 }
6959
6960 if (ioc->bus_type == FC) {
6961 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6962 "skipping, because the bus type is FC!\n", ioc->name));
6963 return -1;
6964 }
6965
6966 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6967 if (ioc->ioc_reset_in_progress) {
6968 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6969 return -1;
6970 }
6971 ioc->ioc_reset_in_progress = 1;
6972 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6973
6974 rc = -1;
6975
6976 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6977 if (MptResetHandlers[cb_idx])
6978 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
6979 }
6980
6981 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6982 if (ioc->taskmgmt_in_progress) {
Kashyap, Desaib9a0f872010-06-17 14:42:39 +05306983 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306984 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6985 return -1;
6986 }
6987 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6988 /* Disable reply interrupts (also blocks FreeQ) */
6989 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
6990 ioc->active = 0;
6991 time_count = jiffies;
6992
6993 rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
6994
6995 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6996 if (MptResetHandlers[cb_idx])
6997 mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
6998 }
6999
7000 if (rc)
7001 goto out;
7002
7003 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
7004 if (ioc_state != MPI_IOC_STATE_READY)
7005 goto out;
7006
7007 for (ii = 0; ii < 5; ii++) {
7008 /* Get IOC facts! Allow 5 retries */
7009 rc = GetIocFacts(ioc, sleepFlag,
7010 MPT_HOSTEVENT_IOC_RECOVER);
7011 if (rc == 0)
7012 break;
7013 if (sleepFlag == CAN_SLEEP)
7014 msleep(100);
7015 else
7016 mdelay(100);
7017 }
7018 if (ii == 5)
7019 goto out;
7020
7021 rc = PrimeIocFifos(ioc);
7022 if (rc != 0)
7023 goto out;
7024
7025 rc = SendIocInit(ioc, sleepFlag);
7026 if (rc != 0)
7027 goto out;
7028
7029 rc = SendEventNotification(ioc, 1, sleepFlag);
7030 if (rc != 0)
7031 goto out;
7032
7033 if (ioc->hard_resets < -1)
7034 ioc->hard_resets++;
7035
7036 /*
7037 * At this point, we know soft reset succeeded.
7038 */
7039
7040 ioc->active = 1;
7041 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
7042
7043 out:
7044 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7045 ioc->ioc_reset_in_progress = 0;
7046 ioc->taskmgmt_quiesce_io = 0;
7047 ioc->taskmgmt_in_progress = 0;
7048 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7049
7050 if (ioc->active) { /* otherwise, hard reset coming */
7051 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7052 if (MptResetHandlers[cb_idx])
7053 mpt_signal_reset(cb_idx, ioc,
7054 MPT_IOC_POST_RESET);
7055 }
7056 }
7057
7058 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7059 "SoftResetHandler: completed (%d seconds): %s\n",
7060 ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,
7061 ((rc == 0) ? "SUCCESS" : "FAILED")));
7062
7063 return rc;
7064}
7065
7066/**
7067 * mpt_Soft_Hard_ResetHandler - Try less expensive reset
7068 * @ioc: Pointer to MPT_ADAPTER structure
7069 * @sleepFlag: Indicates if sleep or schedule must be called.
7070
7071 *
7072 * Returns 0 for SUCCESS or -1 if FAILED.
7073 * Try for softreset first, only if it fails go for expensive
7074 * HardReset.
7075 **/
7076int
7077mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag) {
7078 int ret = -1;
7079
7080 ret = mpt_SoftResetHandler(ioc, sleepFlag);
7081 if (ret == 0)
7082 return ret;
7083 ret = mpt_HardResetHandler(ioc, sleepFlag);
7084 return ret;
7085}
7086EXPORT_SYMBOL(mpt_Soft_Hard_ResetHandler);
7087
Linus Torvalds1da177e2005-04-16 15:20:36 -07007088/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7089/*
7090 * Reset Handling
7091 */
7092/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7093/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007094 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07007095 * @ioc: Pointer to MPT_ADAPTER structure
7096 * @sleepFlag: Indicates if sleep or schedule must be called.
7097 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007098 * Issues SCSI Task Management call based on input arg values.
7099 * If TaskMgmt fails, returns associated SCSI request.
7100 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07007101 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
7102 * or a non-interrupt thread. In the former, must not call schedule().
7103 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007104 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07007105 * FW reload/initialization failed.
7106 *
7107 * Returns 0 for SUCCESS or -1 if FAILED.
7108 */
7109int
7110mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
7111{
Kashyap, Desaid1306912009-08-05 12:53:51 +05307112 int rc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307113 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007114 unsigned long flags;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307115 unsigned long time_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007116
Prakash, Sathya436ace72007-07-24 15:42:08 +05307117 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007118#ifdef MFCNT
7119 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
7120 printk("MF count 0x%x !\n", ioc->mfcnt);
7121#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05307122 if (mpt_fwfault_debug)
7123 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007124
7125 /* Reset the adapter. Prevent more than 1 call to
7126 * mpt_do_ioc_recovery at any instant in time.
7127 */
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307128 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7129 if (ioc->ioc_reset_in_progress) {
7130 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007131 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007132 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307133 ioc->ioc_reset_in_progress = 1;
7134 if (ioc->alt_ioc)
7135 ioc->alt_ioc->ioc_reset_in_progress = 1;
7136 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007137
Linus Torvalds1da177e2005-04-16 15:20:36 -07007138
7139 /* The SCSI driver needs to adjust timeouts on all current
7140 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02007141 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007142 * For all other protocol drivers, this is a no-op.
7143 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05307144 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7145 if (MptResetHandlers[cb_idx]) {
7146 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
7147 if (ioc->alt_ioc)
7148 mpt_signal_reset(cb_idx, ioc->alt_ioc,
7149 MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007150 }
7151 }
7152
Kashyap, Desai2f187862009-05-29 16:52:37 +05307153 time_count = jiffies;
7154 rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
7155 if (rc != 0) {
7156 printk(KERN_WARNING MYNAM
Kei Tokunaga97009a22010-06-22 19:01:51 +09007157 ": WARNING - (%d) Cannot recover %s, doorbell=0x%08x\n",
7158 rc, ioc->name, mpt_GetIocState(ioc, 0));
Kashyap, Desai2f187862009-05-29 16:52:37 +05307159 } else {
7160 if (ioc->hard_resets < -1)
7161 ioc->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007162 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007163
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307164 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7165 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307166 ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307167 ioc->taskmgmt_in_progress = 0;
7168 if (ioc->alt_ioc) {
7169 ioc->alt_ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307170 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307171 ioc->alt_ioc->taskmgmt_in_progress = 0;
7172 }
7173 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007174
Kashyap, Desaid1306912009-08-05 12:53:51 +05307175 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7176 if (MptResetHandlers[cb_idx]) {
7177 mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
7178 if (ioc->alt_ioc)
7179 mpt_signal_reset(cb_idx,
7180 ioc->alt_ioc, MPT_IOC_POST_RESET);
7181 }
7182 }
7183
Kashyap, Desai2f187862009-05-29 16:52:37 +05307184 dtmprintk(ioc,
7185 printk(MYIOC_s_DEBUG_FMT
7186 "HardResetHandler: completed (%d seconds): %s\n", ioc->name,
7187 jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?
7188 "SUCCESS" : "FAILED")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007189
7190 return rc;
7191}
7192
Kashyap, Desai2f187862009-05-29 16:52:37 +05307193#ifdef CONFIG_FUSION_LOGGING
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007194static void
Kashyap, Desai2f187862009-05-29 16:52:37 +05307195mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007196{
Eric Moore509e5e52006-04-26 13:22:37 -06007197 char *ds = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307198 u32 evData0;
7199 int ii;
7200 u8 event;
7201 char *evStr = ioc->evStr;
7202
7203 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7204 evData0 = le32_to_cpu(pEventReply->Data[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007205
7206 switch(event) {
7207 case MPI_EVENT_NONE:
7208 ds = "None";
7209 break;
7210 case MPI_EVENT_LOG_DATA:
7211 ds = "Log Data";
7212 break;
7213 case MPI_EVENT_STATE_CHANGE:
7214 ds = "State Change";
7215 break;
7216 case MPI_EVENT_UNIT_ATTENTION:
7217 ds = "Unit Attention";
7218 break;
7219 case MPI_EVENT_IOC_BUS_RESET:
7220 ds = "IOC Bus Reset";
7221 break;
7222 case MPI_EVENT_EXT_BUS_RESET:
7223 ds = "External Bus Reset";
7224 break;
7225 case MPI_EVENT_RESCAN:
7226 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007227 break;
7228 case MPI_EVENT_LINK_STATUS_CHANGE:
7229 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
7230 ds = "Link Status(FAILURE) Change";
7231 else
7232 ds = "Link Status(ACTIVE) Change";
7233 break;
7234 case MPI_EVENT_LOOP_STATE_CHANGE:
7235 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
7236 ds = "Loop State(LIP) Change";
7237 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Kashyap, Desai2f187862009-05-29 16:52:37 +05307238 ds = "Loop State(LPE) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007239 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05307240 ds = "Loop State(LPB) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007241 break;
7242 case MPI_EVENT_LOGOUT:
7243 ds = "Logout";
7244 break;
7245 case MPI_EVENT_EVENT_CHANGE:
7246 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06007247 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007248 else
Eric Moore4f766dc2006-07-11 17:24:07 -06007249 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007250 break;
7251 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007252 {
7253 u8 ReasonCode = (u8)(evData0 >> 16);
7254 switch (ReasonCode) {
7255 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
7256 ds = "Integrated Raid: Volume Created";
7257 break;
7258 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
7259 ds = "Integrated Raid: Volume Deleted";
7260 break;
7261 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
7262 ds = "Integrated Raid: Volume Settings Changed";
7263 break;
7264 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
7265 ds = "Integrated Raid: Volume Status Changed";
7266 break;
7267 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
7268 ds = "Integrated Raid: Volume Physdisk Changed";
7269 break;
7270 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
7271 ds = "Integrated Raid: Physdisk Created";
7272 break;
7273 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
7274 ds = "Integrated Raid: Physdisk Deleted";
7275 break;
7276 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
7277 ds = "Integrated Raid: Physdisk Settings Changed";
7278 break;
7279 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
7280 ds = "Integrated Raid: Physdisk Status Changed";
7281 break;
7282 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
7283 ds = "Integrated Raid: Domain Validation Needed";
7284 break;
7285 case MPI_EVENT_RAID_RC_SMART_DATA :
7286 ds = "Integrated Raid; Smart Data";
7287 break;
7288 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
7289 ds = "Integrated Raid: Replace Action Started";
7290 break;
7291 default:
7292 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007293 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007294 }
7295 break;
7296 }
7297 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
7298 ds = "SCSI Device Status Change";
7299 break;
7300 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
7301 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007302 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007303 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007304 u8 ReasonCode = (u8)(evData0 >> 16);
7305 switch (ReasonCode) {
7306 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007307 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007308 "SAS Device Status Change: Added: "
7309 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007310 break;
7311 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06007312 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007313 "SAS Device Status Change: Deleted: "
7314 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007315 break;
7316 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06007317 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007318 "SAS Device Status Change: SMART Data: "
7319 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007320 break;
7321 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007322 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007323 "SAS Device Status Change: No Persistancy: "
7324 "id=%d channel=%d", id, channel);
7325 break;
7326 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
7327 snprintf(evStr, EVENT_DESCR_STR_SZ,
7328 "SAS Device Status Change: Unsupported Device "
7329 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007330 break;
7331 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
7332 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007333 "SAS Device Status Change: Internal Device "
7334 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007335 break;
7336 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
7337 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007338 "SAS Device Status Change: Internal Task "
7339 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007340 break;
7341 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
7342 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007343 "SAS Device Status Change: Internal Abort "
7344 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007345 break;
7346 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
7347 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007348 "SAS Device Status Change: Internal Clear "
7349 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007350 break;
7351 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
7352 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007353 "SAS Device Status Change: Internal Query "
7354 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007355 break;
7356 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007357 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007358 "SAS Device Status Change: Unknown: "
7359 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06007360 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007361 }
7362 break;
7363 }
7364 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
7365 ds = "Bus Timer Expired";
7366 break;
7367 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07007368 {
7369 u16 curr_depth = (u16)(evData0 >> 16);
7370 u8 channel = (u8)(evData0 >> 8);
7371 u8 id = (u8)(evData0);
7372
7373 snprintf(evStr, EVENT_DESCR_STR_SZ,
7374 "Queue Full: channel=%d id=%d depth=%d",
7375 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007376 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07007377 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007378 case MPI_EVENT_SAS_SES:
7379 ds = "SAS SES Event";
7380 break;
7381 case MPI_EVENT_PERSISTENT_TABLE_FULL:
7382 ds = "Persistent Table Full";
7383 break;
7384 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07007385 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007386 u8 LinkRates = (u8)(evData0 >> 8);
7387 u8 PhyNumber = (u8)(evData0);
7388 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
7389 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
7390 switch (LinkRates) {
7391 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06007392 snprintf(evStr, EVENT_DESCR_STR_SZ,
7393 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007394 " Rate Unknown",PhyNumber);
7395 break;
7396 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06007397 snprintf(evStr, EVENT_DESCR_STR_SZ,
7398 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007399 " Phy Disabled",PhyNumber);
7400 break;
7401 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06007402 snprintf(evStr, EVENT_DESCR_STR_SZ,
7403 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007404 " Failed Speed Nego",PhyNumber);
7405 break;
7406 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06007407 snprintf(evStr, EVENT_DESCR_STR_SZ,
7408 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007409 " Sata OOB Completed",PhyNumber);
7410 break;
7411 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06007412 snprintf(evStr, EVENT_DESCR_STR_SZ,
7413 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007414 " Rate 1.5 Gbps",PhyNumber);
7415 break;
7416 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06007417 snprintf(evStr, EVENT_DESCR_STR_SZ,
7418 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007419 " Rate 3.0 Gpbs",PhyNumber);
7420 break;
7421 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007422 snprintf(evStr, EVENT_DESCR_STR_SZ,
7423 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007424 break;
7425 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007426 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007427 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007428 case MPI_EVENT_SAS_DISCOVERY_ERROR:
7429 ds = "SAS Discovery Error";
7430 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007431 case MPI_EVENT_IR_RESYNC_UPDATE:
7432 {
7433 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06007434 snprintf(evStr, EVENT_DESCR_STR_SZ,
7435 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07007436 break;
7437 }
7438 case MPI_EVENT_IR2:
7439 {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307440 u8 id = (u8)(evData0);
7441 u8 channel = (u8)(evData0 >> 8);
7442 u8 phys_num = (u8)(evData0 >> 24);
Moore, Eric3a892be2006-03-14 09:14:03 -07007443 u8 ReasonCode = (u8)(evData0 >> 16);
Kashyap, Desai2f187862009-05-29 16:52:37 +05307444
Moore, Eric3a892be2006-03-14 09:14:03 -07007445 switch (ReasonCode) {
7446 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307447 snprintf(evStr, EVENT_DESCR_STR_SZ,
7448 "IR2: LD State Changed: "
7449 "id=%d channel=%d phys_num=%d",
7450 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007451 break;
7452 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307453 snprintf(evStr, EVENT_DESCR_STR_SZ,
7454 "IR2: PD State Changed "
7455 "id=%d channel=%d phys_num=%d",
7456 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007457 break;
7458 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307459 snprintf(evStr, EVENT_DESCR_STR_SZ,
7460 "IR2: Bad Block Table Full: "
7461 "id=%d channel=%d phys_num=%d",
7462 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007463 break;
7464 case MPI_EVENT_IR2_RC_PD_INSERTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307465 snprintf(evStr, EVENT_DESCR_STR_SZ,
7466 "IR2: PD Inserted: "
7467 "id=%d channel=%d phys_num=%d",
7468 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007469 break;
7470 case MPI_EVENT_IR2_RC_PD_REMOVED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307471 snprintf(evStr, EVENT_DESCR_STR_SZ,
7472 "IR2: PD Removed: "
7473 "id=%d channel=%d phys_num=%d",
7474 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007475 break;
7476 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307477 snprintf(evStr, EVENT_DESCR_STR_SZ,
7478 "IR2: Foreign CFG Detected: "
7479 "id=%d channel=%d phys_num=%d",
7480 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007481 break;
7482 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307483 snprintf(evStr, EVENT_DESCR_STR_SZ,
7484 "IR2: Rebuild Medium Error: "
7485 "id=%d channel=%d phys_num=%d",
7486 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007487 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05307488 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
7489 snprintf(evStr, EVENT_DESCR_STR_SZ,
7490 "IR2: Dual Port Added: "
7491 "id=%d channel=%d phys_num=%d",
7492 id, channel, phys_num);
7493 break;
7494 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
7495 snprintf(evStr, EVENT_DESCR_STR_SZ,
7496 "IR2: Dual Port Removed: "
7497 "id=%d channel=%d phys_num=%d",
7498 id, channel, phys_num);
7499 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007500 default:
7501 ds = "IR2";
7502 break;
7503 }
7504 break;
7505 }
7506 case MPI_EVENT_SAS_DISCOVERY:
7507 {
7508 if (evData0)
7509 ds = "SAS Discovery: Start";
7510 else
7511 ds = "SAS Discovery: Stop";
7512 break;
7513 }
7514 case MPI_EVENT_LOG_ENTRY_ADDED:
7515 ds = "SAS Log Entry Added";
7516 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007517
Eric Moorec6c727a2007-01-29 09:44:54 -07007518 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
7519 {
7520 u8 phy_num = (u8)(evData0);
7521 u8 port_num = (u8)(evData0 >> 8);
7522 u8 port_width = (u8)(evData0 >> 16);
7523 u8 primative = (u8)(evData0 >> 24);
7524 snprintf(evStr, EVENT_DESCR_STR_SZ,
7525 "SAS Broadcase Primative: phy=%d port=%d "
7526 "width=%d primative=0x%02x",
7527 phy_num, port_num, port_width, primative);
7528 break;
7529 }
7530
7531 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7532 {
7533 u8 reason = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007534
Kashyap, Desai2f187862009-05-29 16:52:37 +05307535 switch (reason) {
7536 case MPI_EVENT_SAS_INIT_RC_ADDED:
7537 ds = "SAS Initiator Status Change: Added";
7538 break;
7539 case MPI_EVENT_SAS_INIT_RC_REMOVED:
7540 ds = "SAS Initiator Status Change: Deleted";
7541 break;
7542 default:
7543 ds = "SAS Initiator Status Change";
7544 break;
7545 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007546 break;
7547 }
7548
7549 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7550 {
7551 u8 max_init = (u8)(evData0);
7552 u8 current_init = (u8)(evData0 >> 8);
7553
7554 snprintf(evStr, EVENT_DESCR_STR_SZ,
7555 "SAS Initiator Device Table Overflow: max initiators=%02d "
7556 "current initators=%02d",
7557 max_init, current_init);
7558 break;
7559 }
7560 case MPI_EVENT_SAS_SMP_ERROR:
7561 {
7562 u8 status = (u8)(evData0);
7563 u8 port_num = (u8)(evData0 >> 8);
7564 u8 result = (u8)(evData0 >> 16);
7565
7566 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7567 snprintf(evStr, EVENT_DESCR_STR_SZ,
7568 "SAS SMP Error: port=%d result=0x%02x",
7569 port_num, result);
7570 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7571 snprintf(evStr, EVENT_DESCR_STR_SZ,
7572 "SAS SMP Error: port=%d : CRC Error",
7573 port_num);
7574 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7575 snprintf(evStr, EVENT_DESCR_STR_SZ,
7576 "SAS SMP Error: port=%d : Timeout",
7577 port_num);
7578 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7579 snprintf(evStr, EVENT_DESCR_STR_SZ,
7580 "SAS SMP Error: port=%d : No Destination",
7581 port_num);
7582 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7583 snprintf(evStr, EVENT_DESCR_STR_SZ,
7584 "SAS SMP Error: port=%d : Bad Destination",
7585 port_num);
7586 else
7587 snprintf(evStr, EVENT_DESCR_STR_SZ,
7588 "SAS SMP Error: port=%d : status=0x%02x",
7589 port_num, status);
7590 break;
7591 }
7592
Kashyap, Desai2f187862009-05-29 16:52:37 +05307593 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
7594 {
7595 u8 reason = (u8)(evData0);
7596
7597 switch (reason) {
7598 case MPI_EVENT_SAS_EXP_RC_ADDED:
7599 ds = "Expander Status Change: Added";
7600 break;
7601 case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
7602 ds = "Expander Status Change: Deleted";
7603 break;
7604 default:
7605 ds = "Expander Status Change";
7606 break;
7607 }
7608 break;
7609 }
7610
Linus Torvalds1da177e2005-04-16 15:20:36 -07007611 /*
7612 * MPT base "custom" events may be added here...
7613 */
7614 default:
7615 ds = "Unknown";
7616 break;
7617 }
Eric Moore509e5e52006-04-26 13:22:37 -06007618 if (ds)
7619 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007620
Kashyap, Desai2f187862009-05-29 16:52:37 +05307621
7622 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7623 "MPT event:(%02Xh) : %s\n",
7624 ioc->name, event, evStr));
7625
7626 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
7627 ": Event data:\n"));
7628 for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
7629 devtverboseprintk(ioc, printk(" %08x",
7630 le32_to_cpu(pEventReply->Data[ii])));
7631 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
7632}
7633#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007634/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007635/**
7636 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007637 * @ioc: Pointer to MPT_ADAPTER structure
7638 * @pEventReply: Pointer to EventNotification reply frame
7639 * @evHandlers: Pointer to integer, number of event handlers
7640 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007641 * Routes a received EventNotificationReply to all currently registered
7642 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007643 * Returns sum of event handlers return values.
7644 */
7645static int
7646ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7647{
7648 u16 evDataLen;
7649 u32 evData0 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007650 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307651 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007652 int r = 0;
7653 int handlers = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007654 u8 event;
7655
7656 /*
7657 * Do platform normalization of values
7658 */
7659 event = le32_to_cpu(pEventReply->Event) & 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007660 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7661 if (evDataLen) {
7662 evData0 = le32_to_cpu(pEventReply->Data[0]);
7663 }
7664
Prakash, Sathya436ace72007-07-24 15:42:08 +05307665#ifdef CONFIG_FUSION_LOGGING
Kashyap, Desai2f187862009-05-29 16:52:37 +05307666 if (evDataLen)
7667 mpt_display_event_info(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007668#endif
7669
7670 /*
7671 * Do general / base driver event processing
7672 */
7673 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007674 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7675 if (evDataLen) {
7676 u8 evState = evData0 & 0xFF;
7677
7678 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7679
7680 /* Update EventState field in cached IocFacts */
7681 if (ioc->facts.Function) {
7682 ioc->facts.EventState = evState;
7683 }
7684 }
7685 break;
Moore, Ericece50912006-01-16 18:53:19 -07007686 case MPI_EVENT_INTEGRATED_RAID:
7687 mptbase_raid_process_event_data(ioc,
7688 (MpiEventDataRaid_t *)pEventReply->Data);
7689 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007690 default:
7691 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007692 }
7693
7694 /*
7695 * Should this event be logged? Events are written sequentially.
7696 * When buffer is full, start again at the top.
7697 */
7698 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7699 int idx;
7700
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007701 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007702
7703 ioc->events[idx].event = event;
7704 ioc->events[idx].eventContext = ioc->eventContext;
7705
7706 for (ii = 0; ii < 2; ii++) {
7707 if (ii < evDataLen)
7708 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7709 else
7710 ioc->events[idx].data[ii] = 0;
7711 }
7712
7713 ioc->eventContext++;
7714 }
7715
7716
7717 /*
7718 * Call each currently registered protocol event handler.
7719 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007720 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307721 if (MptEvHandlers[cb_idx]) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307722 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7723 "Routing Event to event handler #%d\n",
7724 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307725 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007726 handlers++;
7727 }
7728 }
7729 /* FIXME? Examine results here? */
7730
7731 /*
7732 * If needed, send (a single) EventAck.
7733 */
7734 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307735 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007736 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007737 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307738 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007739 ioc->name, ii));
7740 }
7741 }
7742
7743 *evHandlers = handlers;
7744 return r;
7745}
7746
7747/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007748/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007749 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7750 * @ioc: Pointer to MPT_ADAPTER structure
7751 * @log_info: U32 LogInfo reply word from the IOC
7752 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007753 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007754 */
7755static void
7756mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7757{
Eric Moore7c431e52007-06-13 16:34:36 -06007758 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007759
Eric Moore7c431e52007-06-13 16:34:36 -06007760 switch (log_info & 0xFF000000) {
7761 case MPI_IOCLOGINFO_FC_INIT_BASE:
7762 desc = "FCP Initiator";
7763 break;
7764 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7765 desc = "FCP Target";
7766 break;
7767 case MPI_IOCLOGINFO_FC_LAN_BASE:
7768 desc = "LAN";
7769 break;
7770 case MPI_IOCLOGINFO_FC_MSG_BASE:
7771 desc = "MPI Message Layer";
7772 break;
7773 case MPI_IOCLOGINFO_FC_LINK_BASE:
7774 desc = "FC Link";
7775 break;
7776 case MPI_IOCLOGINFO_FC_CTX_BASE:
7777 desc = "Context Manager";
7778 break;
7779 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7780 desc = "Invalid Field Offset";
7781 break;
7782 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7783 desc = "State Change Info";
7784 break;
7785 }
7786
7787 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7788 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007789}
7790
7791/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007792/**
Moore, Eric335a9412006-01-17 17:06:23 -07007793 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007794 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007795 * @log_info: U32 LogInfo word from the IOC
7796 *
7797 * Refer to lsi/sp_log.h.
7798 */
7799static void
Moore, Eric335a9412006-01-17 17:06:23 -07007800mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007801{
7802 u32 info = log_info & 0x00FF0000;
7803 char *desc = "unknown";
7804
7805 switch (info) {
7806 case 0x00010000:
7807 desc = "bug! MID not found";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007808 break;
7809
7810 case 0x00020000:
7811 desc = "Parity Error";
7812 break;
7813
7814 case 0x00030000:
7815 desc = "ASYNC Outbound Overrun";
7816 break;
7817
7818 case 0x00040000:
7819 desc = "SYNC Offset Error";
7820 break;
7821
7822 case 0x00050000:
7823 desc = "BM Change";
7824 break;
7825
7826 case 0x00060000:
7827 desc = "Msg In Overflow";
7828 break;
7829
7830 case 0x00070000:
7831 desc = "DMA Error";
7832 break;
7833
7834 case 0x00080000:
7835 desc = "Outbound DMA Overrun";
7836 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007837
Linus Torvalds1da177e2005-04-16 15:20:36 -07007838 case 0x00090000:
7839 desc = "Task Management";
7840 break;
7841
7842 case 0x000A0000:
7843 desc = "Device Problem";
7844 break;
7845
7846 case 0x000B0000:
7847 desc = "Invalid Phase Change";
7848 break;
7849
7850 case 0x000C0000:
7851 desc = "Untagged Table Size";
7852 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007853
Linus Torvalds1da177e2005-04-16 15:20:36 -07007854 }
7855
7856 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7857}
7858
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007859/* strings for sas loginfo */
7860 static char *originator_str[] = {
7861 "IOP", /* 00h */
7862 "PL", /* 01h */
7863 "IR" /* 02h */
7864 };
7865 static char *iop_code_str[] = {
7866 NULL, /* 00h */
7867 "Invalid SAS Address", /* 01h */
7868 NULL, /* 02h */
7869 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007870 "Diag Message Error", /* 04h */
7871 "Task Terminated", /* 05h */
7872 "Enclosure Management", /* 06h */
7873 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007874 };
7875 static char *pl_code_str[] = {
7876 NULL, /* 00h */
7877 "Open Failure", /* 01h */
7878 "Invalid Scatter Gather List", /* 02h */
7879 "Wrong Relative Offset or Frame Length", /* 03h */
7880 "Frame Transfer Error", /* 04h */
7881 "Transmit Frame Connected Low", /* 05h */
7882 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7883 "SATA Read Log Receive Data Error", /* 07h */
7884 "SATA NCQ Fail All Commands After Error", /* 08h */
7885 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7886 "Receive Frame Invalid Message", /* 0Ah */
7887 "Receive Context Message Valid Error", /* 0Bh */
7888 "Receive Frame Current Frame Error", /* 0Ch */
7889 "SATA Link Down", /* 0Dh */
7890 "Discovery SATA Init W IOS", /* 0Eh */
7891 "Config Invalid Page", /* 0Fh */
7892 "Discovery SATA Init Timeout", /* 10h */
7893 "Reset", /* 11h */
7894 "Abort", /* 12h */
7895 "IO Not Yet Executed", /* 13h */
7896 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007897 "Persistent Reservation Out Not Affiliation "
7898 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007899 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007900 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007901 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007902 NULL, /* 19h */
7903 NULL, /* 1Ah */
7904 NULL, /* 1Bh */
7905 NULL, /* 1Ch */
7906 NULL, /* 1Dh */
7907 NULL, /* 1Eh */
7908 NULL, /* 1Fh */
7909 "Enclosure Management" /* 20h */
7910 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007911 static char *ir_code_str[] = {
7912 "Raid Action Error", /* 00h */
7913 NULL, /* 00h */
7914 NULL, /* 01h */
7915 NULL, /* 02h */
7916 NULL, /* 03h */
7917 NULL, /* 04h */
7918 NULL, /* 05h */
7919 NULL, /* 06h */
7920 NULL /* 07h */
7921 };
7922 static char *raid_sub_code_str[] = {
7923 NULL, /* 00h */
7924 "Volume Creation Failed: Data Passed too "
7925 "Large", /* 01h */
7926 "Volume Creation Failed: Duplicate Volumes "
7927 "Attempted", /* 02h */
7928 "Volume Creation Failed: Max Number "
7929 "Supported Volumes Exceeded", /* 03h */
7930 "Volume Creation Failed: DMA Error", /* 04h */
7931 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7932 "Volume Creation Failed: Error Reading "
7933 "MFG Page 4", /* 06h */
7934 "Volume Creation Failed: Creating Internal "
7935 "Structures", /* 07h */
7936 NULL, /* 08h */
7937 NULL, /* 09h */
7938 NULL, /* 0Ah */
7939 NULL, /* 0Bh */
7940 NULL, /* 0Ch */
7941 NULL, /* 0Dh */
7942 NULL, /* 0Eh */
7943 NULL, /* 0Fh */
7944 "Activation failed: Already Active Volume", /* 10h */
7945 "Activation failed: Unsupported Volume Type", /* 11h */
7946 "Activation failed: Too Many Active Volumes", /* 12h */
7947 "Activation failed: Volume ID in Use", /* 13h */
7948 "Activation failed: Reported Failure", /* 14h */
7949 "Activation failed: Importing a Volume", /* 15h */
7950 NULL, /* 16h */
7951 NULL, /* 17h */
7952 NULL, /* 18h */
7953 NULL, /* 19h */
7954 NULL, /* 1Ah */
7955 NULL, /* 1Bh */
7956 NULL, /* 1Ch */
7957 NULL, /* 1Dh */
7958 NULL, /* 1Eh */
7959 NULL, /* 1Fh */
7960 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7961 "Phys Disk failed: Data Passed too Large", /* 21h */
7962 "Phys Disk failed: DMA Error", /* 22h */
7963 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7964 "Phys Disk failed: Creating Phys Disk Config "
7965 "Page", /* 24h */
7966 NULL, /* 25h */
7967 NULL, /* 26h */
7968 NULL, /* 27h */
7969 NULL, /* 28h */
7970 NULL, /* 29h */
7971 NULL, /* 2Ah */
7972 NULL, /* 2Bh */
7973 NULL, /* 2Ch */
7974 NULL, /* 2Dh */
7975 NULL, /* 2Eh */
7976 NULL, /* 2Fh */
7977 "Compatibility Error: IR Disabled", /* 30h */
7978 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7979 "Compatibility Error: Device not Direct Access "
7980 "Device ", /* 32h */
7981 "Compatibility Error: Removable Device Found", /* 33h */
7982 "Compatibility Error: Device SCSI Version not "
7983 "2 or Higher", /* 34h */
7984 "Compatibility Error: SATA Device, 48 BIT LBA "
7985 "not Supported", /* 35h */
7986 "Compatibility Error: Device doesn't have "
7987 "512 Byte Block Sizes", /* 36h */
7988 "Compatibility Error: Volume Type Check Failed", /* 37h */
7989 "Compatibility Error: Volume Type is "
7990 "Unsupported by FW", /* 38h */
7991 "Compatibility Error: Disk Drive too Small for "
7992 "use in Volume", /* 39h */
7993 "Compatibility Error: Phys Disk for Create "
7994 "Volume not Found", /* 3Ah */
7995 "Compatibility Error: Too Many or too Few "
7996 "Disks for Volume Type", /* 3Bh */
7997 "Compatibility Error: Disk stripe Sizes "
7998 "Must be 64KB", /* 3Ch */
7999 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
8000 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008001
8002/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008003/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008004 * mpt_sas_log_info - Log information returned from SAS IOC.
8005 * @ioc: Pointer to MPT_ADAPTER structure
8006 * @log_info: U32 LogInfo reply word from the IOC
8007 *
8008 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008009 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008010static void
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308011mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info, u8 cb_idx)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008012{
8013union loginfo_type {
8014 u32 loginfo;
8015 struct {
8016 u32 subcode:16;
8017 u32 code:8;
8018 u32 originator:4;
8019 u32 bus_type:4;
8020 }dw;
8021};
8022 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07008023 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008024 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07008025 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008026
8027 sas_loginfo.loginfo = log_info;
8028 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008029 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008030 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07008031
8032 originator_desc = originator_str[sas_loginfo.dw.originator];
8033
8034 switch (sas_loginfo.dw.originator) {
8035
8036 case 0: /* IOP */
8037 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008038 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008039 code_desc = iop_code_str[sas_loginfo.dw.code];
8040 break;
8041 case 1: /* PL */
8042 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008043 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008044 code_desc = pl_code_str[sas_loginfo.dw.code];
8045 break;
8046 case 2: /* IR */
8047 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008048 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008049 break;
8050 code_desc = ir_code_str[sas_loginfo.dw.code];
8051 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008052 ARRAY_SIZE(raid_sub_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008053 break;
8054 if (sas_loginfo.dw.code == 0)
8055 sub_code_desc =
8056 raid_sub_code_str[sas_loginfo.dw.subcode];
8057 break;
8058 default:
8059 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008060 }
8061
Eric Moorec6c727a2007-01-29 09:44:54 -07008062 if (sub_code_desc != NULL)
8063 printk(MYIOC_s_INFO_FMT
8064 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308065 " SubCode={%s} cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008066 ioc->name, log_info, originator_desc, code_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308067 sub_code_desc, MptCallbacksName[cb_idx]);
Eric Moorec6c727a2007-01-29 09:44:54 -07008068 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008069 printk(MYIOC_s_INFO_FMT
8070 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308071 " SubCode(0x%04x) cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008072 ioc->name, log_info, originator_desc, code_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308073 sas_loginfo.dw.subcode, MptCallbacksName[cb_idx]);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008074 else
8075 printk(MYIOC_s_INFO_FMT
8076 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308077 " SubCode(0x%04x) cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008078 ioc->name, log_info, originator_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308079 sas_loginfo.dw.code, sas_loginfo.dw.subcode,
8080 MptCallbacksName[cb_idx]);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008081}
8082
Linus Torvalds1da177e2005-04-16 15:20:36 -07008083/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008084/**
Eric Moorec6c727a2007-01-29 09:44:54 -07008085 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
8086 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08008087 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07008088 * @mf: Pointer to MPT request frame
8089 *
8090 * Refer to lsi/mpi.h.
8091 **/
8092static void
8093mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
8094{
8095 Config_t *pReq = (Config_t *)mf;
8096 char extend_desc[EVENT_DESCR_STR_SZ];
8097 char *desc = NULL;
8098 u32 form;
8099 u8 page_type;
8100
8101 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
8102 page_type = pReq->ExtPageType;
8103 else
8104 page_type = pReq->Header.PageType;
8105
8106 /*
8107 * ignore invalid page messages for GET_NEXT_HANDLE
8108 */
8109 form = le32_to_cpu(pReq->PageAddress);
8110 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
8111 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
8112 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
8113 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
8114 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
8115 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
8116 return;
8117 }
8118 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
8119 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
8120 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
8121 return;
8122 }
8123
8124 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
8125 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
8126 page_type, pReq->Header.PageNumber, pReq->Action, form);
8127
8128 switch (ioc_status) {
8129
8130 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8131 desc = "Config Page Invalid Action";
8132 break;
8133
8134 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8135 desc = "Config Page Invalid Type";
8136 break;
8137
8138 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8139 desc = "Config Page Invalid Page";
8140 break;
8141
8142 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8143 desc = "Config Page Invalid Data";
8144 break;
8145
8146 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8147 desc = "Config Page No Defaults";
8148 break;
8149
8150 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
8151 desc = "Config Page Can't Commit";
8152 break;
8153 }
8154
8155 if (!desc)
8156 return;
8157
Eric Moore29dd3602007-09-14 18:46:51 -06008158 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
8159 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07008160}
8161
8162/**
8163 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07008164 * @ioc: Pointer to MPT_ADAPTER structure
8165 * @ioc_status: U32 IOCStatus word from IOC
8166 * @mf: Pointer to MPT request frame
8167 *
8168 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008169 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07008170static void
Eric Moorec6c727a2007-01-29 09:44:54 -07008171mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008172{
8173 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06008174 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008175
8176 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07008177
8178/****************************************************************************/
8179/* Common IOCStatus values for all replies */
8180/****************************************************************************/
8181
Linus Torvalds1da177e2005-04-16 15:20:36 -07008182 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
8183 desc = "Invalid Function";
8184 break;
8185
8186 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
8187 desc = "Busy";
8188 break;
8189
8190 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
8191 desc = "Invalid SGL";
8192 break;
8193
8194 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
8195 desc = "Internal Error";
8196 break;
8197
8198 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
8199 desc = "Reserved";
8200 break;
8201
8202 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
8203 desc = "Insufficient Resources";
8204 break;
8205
8206 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
8207 desc = "Invalid Field";
8208 break;
8209
8210 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
8211 desc = "Invalid State";
8212 break;
8213
Eric Moorec6c727a2007-01-29 09:44:54 -07008214/****************************************************************************/
8215/* Config IOCStatus values */
8216/****************************************************************************/
8217
Linus Torvalds1da177e2005-04-16 15:20:36 -07008218 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8219 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8220 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8221 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8222 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8223 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008224 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008225 break;
8226
Eric Moorec6c727a2007-01-29 09:44:54 -07008227/****************************************************************************/
8228/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
8229/* */
8230/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
8231/* */
8232/****************************************************************************/
8233
Linus Torvalds1da177e2005-04-16 15:20:36 -07008234 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008235 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008236 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
8237 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
8238 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
8239 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008240 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008241 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008242 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008243 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008244 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008245 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07008246 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008247 break;
8248
Eric Moorec6c727a2007-01-29 09:44:54 -07008249/****************************************************************************/
8250/* SCSI Target values */
8251/****************************************************************************/
8252
8253 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
8254 desc = "Target: Priority IO";
8255 break;
8256
8257 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
8258 desc = "Target: Invalid Port";
8259 break;
8260
8261 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
8262 desc = "Target Invalid IO Index:";
8263 break;
8264
8265 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
8266 desc = "Target: Aborted";
8267 break;
8268
8269 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
8270 desc = "Target: No Conn Retryable";
8271 break;
8272
8273 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
8274 desc = "Target: No Connection";
8275 break;
8276
8277 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
8278 desc = "Target: Transfer Count Mismatch";
8279 break;
8280
8281 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
8282 desc = "Target: STS Data not Sent";
8283 break;
8284
8285 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
8286 desc = "Target: Data Offset Error";
8287 break;
8288
8289 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
8290 desc = "Target: Too Much Write Data";
8291 break;
8292
8293 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
8294 desc = "Target: IU Too Short";
8295 break;
8296
8297 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
8298 desc = "Target: ACK NAK Timeout";
8299 break;
8300
8301 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
8302 desc = "Target: Nak Received";
8303 break;
8304
8305/****************************************************************************/
8306/* Fibre Channel Direct Access values */
8307/****************************************************************************/
8308
8309 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
8310 desc = "FC: Aborted";
8311 break;
8312
8313 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
8314 desc = "FC: RX ID Invalid";
8315 break;
8316
8317 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
8318 desc = "FC: DID Invalid";
8319 break;
8320
8321 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
8322 desc = "FC: Node Logged Out";
8323 break;
8324
8325 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
8326 desc = "FC: Exchange Canceled";
8327 break;
8328
8329/****************************************************************************/
8330/* LAN values */
8331/****************************************************************************/
8332
8333 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
8334 desc = "LAN: Device not Found";
8335 break;
8336
8337 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
8338 desc = "LAN: Device Failure";
8339 break;
8340
8341 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
8342 desc = "LAN: Transmit Error";
8343 break;
8344
8345 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
8346 desc = "LAN: Transmit Aborted";
8347 break;
8348
8349 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
8350 desc = "LAN: Receive Error";
8351 break;
8352
8353 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
8354 desc = "LAN: Receive Aborted";
8355 break;
8356
8357 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
8358 desc = "LAN: Partial Packet";
8359 break;
8360
8361 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
8362 desc = "LAN: Canceled";
8363 break;
8364
8365/****************************************************************************/
8366/* Serial Attached SCSI values */
8367/****************************************************************************/
8368
8369 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
8370 desc = "SAS: SMP Request Failed";
8371 break;
8372
8373 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
8374 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07008375 break;
8376
8377 default:
8378 desc = "Others";
8379 break;
8380 }
Eric Moorec6c727a2007-01-29 09:44:54 -07008381
8382 if (!desc)
8383 return;
8384
Eric Moore29dd3602007-09-14 18:46:51 -06008385 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
8386 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008387}
8388
8389/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008390EXPORT_SYMBOL(mpt_attach);
8391EXPORT_SYMBOL(mpt_detach);
8392#ifdef CONFIG_PM
8393EXPORT_SYMBOL(mpt_resume);
8394EXPORT_SYMBOL(mpt_suspend);
8395#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07008396EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008397EXPORT_SYMBOL(mpt_register);
8398EXPORT_SYMBOL(mpt_deregister);
8399EXPORT_SYMBOL(mpt_event_register);
8400EXPORT_SYMBOL(mpt_event_deregister);
8401EXPORT_SYMBOL(mpt_reset_register);
8402EXPORT_SYMBOL(mpt_reset_deregister);
8403EXPORT_SYMBOL(mpt_device_driver_register);
8404EXPORT_SYMBOL(mpt_device_driver_deregister);
8405EXPORT_SYMBOL(mpt_get_msg_frame);
8406EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05308407EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008408EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008409EXPORT_SYMBOL(mpt_send_handshake_request);
8410EXPORT_SYMBOL(mpt_verify_adapter);
8411EXPORT_SYMBOL(mpt_GetIocState);
8412EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008413EXPORT_SYMBOL(mpt_HardResetHandler);
8414EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008415EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008416EXPORT_SYMBOL(mpt_alloc_fw_memory);
8417EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02008418EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07008419EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008420
Linus Torvalds1da177e2005-04-16 15:20:36 -07008421/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008422/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008423 * fusion_init - Fusion MPT base driver initialization routine.
8424 *
8425 * Returns 0 for success, non-zero for failure.
8426 */
8427static int __init
8428fusion_init(void)
8429{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308430 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008431
8432 show_mptmod_ver(my_NAME, my_VERSION);
8433 printk(KERN_INFO COPYRIGHT "\n");
8434
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308435 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
8436 MptCallbacks[cb_idx] = NULL;
8437 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
8438 MptEvHandlers[cb_idx] = NULL;
8439 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008440 }
8441
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008442 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07008443 * EventNotification handling.
8444 */
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308445 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER,
8446 "mptbase_reply");
Linus Torvalds1da177e2005-04-16 15:20:36 -07008447
8448 /* Register for hard reset handling callbacks.
8449 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05308450 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008451
8452#ifdef CONFIG_PROC_FS
8453 (void) procmpt_create();
8454#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008455 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008456}
8457
8458/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008459/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008460 * fusion_exit - Perform driver unload cleanup.
8461 *
8462 * This routine frees all resources associated with each MPT adapter
8463 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
8464 */
8465static void __exit
8466fusion_exit(void)
8467{
8468
Linus Torvalds1da177e2005-04-16 15:20:36 -07008469 mpt_reset_deregister(mpt_base_index);
8470
8471#ifdef CONFIG_PROC_FS
8472 procmpt_destroy();
8473#endif
8474}
8475
Linus Torvalds1da177e2005-04-16 15:20:36 -07008476module_init(fusion_init);
8477module_exit(fusion_exit);