blob: e319abcd849cb14066fc2c5e82c47ebd379dd37f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptbase.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * This is the Fusion MPT base driver which supports multiple
4 * (SCSI + LAN) specialized protocol drivers.
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05305 * For use with LSI PCI chip/adapter(s)
6 * running LSI Fusion MPT (Message Passing Technology) firmware.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Prakash, Sathyacddc0ab2008-05-21 00:56:41 +05308 * Copyright (c) 1999-2008 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06009 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13/*
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; version 2 of the License.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 NO WARRANTY
24 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
25 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
26 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
27 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
28 solely responsible for determining the appropriateness of using and
29 distributing the Program and assumes all risks associated with its
30 exercise of rights under this Agreement, including but not limited to
31 the risks and costs of program errors, damage to or loss of data,
32 programs or equipment, and unavailability or interruption of operations.
33
34 DISCLAIMER OF LIABILITY
35 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
38 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
40 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
41 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
42
43 You should have received a copy of the GNU General Public License
44 along with this program; if not, write to the Free Software
45 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46*/
47/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/kernel.h>
50#include <linux/module.h>
51#include <linux/errno.h>
52#include <linux/init.h>
53#include <linux/slab.h>
54#include <linux/types.h>
55#include <linux/pci.h>
56#include <linux/kdev_t.h>
57#include <linux/blkdev.h>
58#include <linux/delay.h>
59#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040060#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <asm/io.h>
62#ifdef CONFIG_MTRR
63#include <asm/mtrr.h>
64#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#include "mptbase.h"
Eric Moore7c431e52007-06-13 16:34:36 -060067#include "lsi/mpi_log_fc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT base driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptbase"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/*
80 * cmd line parameters
81 */
Kashyap, Desaie3829682009-01-08 14:27:16 +053082
83static int mpt_msi_enable_spi;
84module_param(mpt_msi_enable_spi, int, 0);
85MODULE_PARM_DESC(mpt_msi_enable_spi, " Enable MSI Support for SPI \
86 controllers (default=0)");
87
88static int mpt_msi_enable_fc;
89module_param(mpt_msi_enable_fc, int, 0);
90MODULE_PARM_DESC(mpt_msi_enable_fc, " Enable MSI Support for FC \
91 controllers (default=0)");
92
93static int mpt_msi_enable_sas;
Yinghai Lu5ce78682009-02-18 11:25:32 -080094module_param(mpt_msi_enable_sas, int, 0);
Kashyap, Desaie3829682009-01-08 14:27:16 +053095MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS \
Yinghai Lu5ce78682009-02-18 11:25:32 -080096 controllers (default=0)");
Kashyap, Desaie3829682009-01-08 14:27:16 +053097
Christoph Hellwig4ddce142006-01-17 13:44:29 +000098
Eric Moore793955f2007-01-29 09:42:20 -070099static int mpt_channel_mapping;
100module_param(mpt_channel_mapping, int, 0);
101MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
102
Prakash, Sathya436ace72007-07-24 15:42:08 +0530103static int mpt_debug_level;
James Bottomleydb47c2d2007-07-28 13:40:21 -0400104static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
105module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
106 &mpt_debug_level, 0600);
Kashyap, Desaie3829682009-01-08 14:27:16 +0530107MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h \
108 - (default=0)");
109
Kashyap, Desai2f4c7822009-01-06 15:03:37 +0530110int mpt_fwfault_debug;
111EXPORT_SYMBOL(mpt_fwfault_debug);
112module_param_call(mpt_fwfault_debug, param_set_int, param_get_int,
113 &mpt_fwfault_debug, 0600);
114MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault"
115 " and halt Firmware on fault - (default=0)");
116
117
Prakash, Sathya436ace72007-07-24 15:42:08 +0530118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119#ifdef MFCNT
120static int mfcounter = 0;
121#define PRINT_MF_COUNT 20000
122#endif
123
124/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
125/*
126 * Public data...
127 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129#define WHOINIT_UNKNOWN 0xAA
130
131/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
132/*
133 * Private data...
134 */
135 /* Adapter link list */
136LIST_HEAD(ioc_list);
137 /* Callback lookup table */
138static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
139 /* Protocol driver class lookup table */
140static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
141 /* Event handler lookup table */
142static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
143 /* Reset handler lookup table */
144static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
145static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
146
Erik Ekmane47c11c2009-12-14 21:21:56 +0100147#ifdef CONFIG_PROC_FS
148static struct proc_dir_entry *mpt_proc_root_dir;
149#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530151/*
152 * Driver Callback Index's
153 */
154static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
155static u8 last_drv_idx;
156
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
158/*
159 * Forward protos...
160 */
David Howells7d12e782006-10-05 14:55:46 +0100161static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530162static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
163 MPT_FRAME_HDR *reply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
165 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
166 int sleepFlag);
167static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
168static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
169static void mpt_adapter_disable(MPT_ADAPTER *ioc);
170static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
171
172static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
173static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
175static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
176static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
177static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
178static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200179static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
181static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
182static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
183static int PrimeIocFifos(MPT_ADAPTER *ioc);
184static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
185static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
186static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
187static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200189int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
191static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
192static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
193static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530194static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Kashyap, Desaifd761752009-05-29 16:39:06 +0530195static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch,
196 int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200198static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
199static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
201#ifdef CONFIG_PROC_FS
202static int procmpt_summary_read(char *buf, char **start, off_t offset,
203 int request, int *eof, void *data);
204static int procmpt_version_read(char *buf, char **start, off_t offset,
205 int request, int *eof, void *data);
206static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
207 int request, int *eof, void *data);
208#endif
209static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
210
Kashyap, Desaifd761752009-05-29 16:39:06 +0530211static int ProcessEventNotification(MPT_ADAPTER *ioc,
212 EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700213static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700215static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600216static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700217static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700218static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
220/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221static int __init fusion_init (void);
222static void __exit fusion_exit (void);
223
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224#define CHIPREG_READ32(addr) readl_relaxed(addr)
225#define CHIPREG_READ32_dmasync(addr) readl(addr)
226#define CHIPREG_WRITE32(addr,val) writel(val, addr)
227#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
228#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
229
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600230static void
231pci_disable_io_access(struct pci_dev *pdev)
232{
233 u16 command_reg;
234
235 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
236 command_reg &= ~1;
237 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
238}
239
240static void
241pci_enable_io_access(struct pci_dev *pdev)
242{
243 u16 command_reg;
244
245 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
246 command_reg |= 1;
247 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
248}
249
James Bottomleydb47c2d2007-07-28 13:40:21 -0400250static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
251{
252 int ret = param_set_int(val, kp);
253 MPT_ADAPTER *ioc;
254
255 if (ret)
256 return ret;
257
258 list_for_each_entry(ioc, &ioc_list, list)
259 ioc->debug_level = mpt_debug_level;
260 return 0;
261}
262
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530263/**
264 * mpt_get_cb_idx - obtain cb_idx for registered driver
265 * @dclass: class driver enum
266 *
267 * Returns cb_idx, or zero means it wasn't found
268 **/
269static u8
270mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
271{
272 u8 cb_idx;
273
274 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
275 if (MptDriverClass[cb_idx] == dclass)
276 return cb_idx;
277 return 0;
278}
279
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530280/**
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530281 * mpt_is_discovery_complete - determine if discovery has completed
282 * @ioc: per adatper instance
283 *
284 * Returns 1 when discovery completed, else zero.
285 */
286static int
287mpt_is_discovery_complete(MPT_ADAPTER *ioc)
288{
289 ConfigExtendedPageHeader_t hdr;
290 CONFIGPARMS cfg;
291 SasIOUnitPage0_t *buffer;
292 dma_addr_t dma_handle;
293 int rc = 0;
294
295 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
296 memset(&cfg, 0, sizeof(CONFIGPARMS));
297 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
298 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
299 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
300 cfg.cfghdr.ehdr = &hdr;
301 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
302
303 if ((mpt_config(ioc, &cfg)))
304 goto out;
305 if (!hdr.ExtPageLength)
306 goto out;
307
308 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
309 &dma_handle);
310 if (!buffer)
311 goto out;
312
313 cfg.physAddr = dma_handle;
314 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
315
316 if ((mpt_config(ioc, &cfg)))
317 goto out_free_consistent;
318
319 if (!(buffer->PhyData[0].PortFlags &
320 MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS))
321 rc = 1;
322
323 out_free_consistent:
324 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
325 buffer, dma_handle);
326 out:
327 return rc;
328}
329
330/**
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530331 * mpt_fault_reset_work - work performed on workq after ioc fault
332 * @work: input argument, used to derive ioc
333 *
334**/
335static void
336mpt_fault_reset_work(struct work_struct *work)
337{
338 MPT_ADAPTER *ioc =
339 container_of(work, MPT_ADAPTER, fault_reset_work.work);
340 u32 ioc_raw_state;
341 int rc;
342 unsigned long flags;
343
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530344 if (ioc->ioc_reset_in_progress || !ioc->active)
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530345 goto out;
346
347 ioc_raw_state = mpt_GetIocState(ioc, 0);
348 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
349 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700350 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530351 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700352 ioc->name, __func__);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530353 rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
354 printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700355 __func__, (rc == 0) ? "success" : "failed");
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530356 ioc_raw_state = mpt_GetIocState(ioc, 0);
357 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
358 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
359 "reset (%04xh)\n", ioc->name, ioc_raw_state &
360 MPI_DOORBELL_DATA_MASK);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530361 } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) {
362 if ((mpt_is_discovery_complete(ioc))) {
363 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing "
364 "discovery_quiesce_io flag\n", ioc->name));
365 ioc->sas_discovery_quiesce_io = 0;
366 }
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530367 }
368
369 out:
370 /*
371 * Take turns polling alternate controller
372 */
373 if (ioc->alt_ioc)
374 ioc = ioc->alt_ioc;
375
376 /* rearm the timer */
Kashyap, Desai2f187862009-05-29 16:52:37 +0530377 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530378 if (ioc->reset_work_q)
379 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
380 msecs_to_jiffies(MPT_POLLING_INTERVAL));
Kashyap, Desai2f187862009-05-29 16:52:37 +0530381 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530382}
383
384
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600385/*
386 * Process turbo (context) reply...
387 */
388static void
389mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
390{
391 MPT_FRAME_HDR *mf = NULL;
392 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530393 u16 req_idx = 0;
394 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600395
Prakash, Sathya436ace72007-07-24 15:42:08 +0530396 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600397 ioc->name, pa));
398
399 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
400 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
401 req_idx = pa & 0x0000FFFF;
402 cb_idx = (pa & 0x00FF0000) >> 16;
403 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
404 break;
405 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530406 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600407 /*
408 * Blind set of mf to NULL here was fatal
409 * after lan_reply says "freeme"
410 * Fix sort of combined with an optimization here;
411 * added explicit check for case where lan_reply
412 * was just returning 1 and doing nothing else.
413 * For this case skip the callback, but set up
414 * proper mf value first here:-)
415 */
416 if ((pa & 0x58000000) == 0x58000000) {
417 req_idx = pa & 0x0000FFFF;
418 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
419 mpt_free_msg_frame(ioc, mf);
420 mb();
421 return;
422 break;
423 }
424 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
425 break;
426 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530427 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600428 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
429 break;
430 default:
431 cb_idx = 0;
432 BUG();
433 }
434
435 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530436 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600437 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600438 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700439 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600440 goto out;
441 }
442
443 if (MptCallbacks[cb_idx](ioc, mf, mr))
444 mpt_free_msg_frame(ioc, mf);
445 out:
446 mb();
447}
448
449static void
450mpt_reply(MPT_ADAPTER *ioc, u32 pa)
451{
452 MPT_FRAME_HDR *mf;
453 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530454 u16 req_idx;
455 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600456 int freeme;
457
458 u32 reply_dma_low;
459 u16 ioc_stat;
460
461 /* non-TURBO reply! Hmmm, something may be up...
462 * Newest turbo reply mechanism; get address
463 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
464 */
465
466 /* Map DMA address of reply header to cpu address.
467 * pa is 32 bits - but the dma address may be 32 or 64 bits
468 * get offset based only only the low addresses
469 */
470
471 reply_dma_low = (pa <<= 1);
472 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
473 (reply_dma_low - ioc->reply_frames_low_dma));
474
475 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
476 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
477 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
478
Prakash, Sathya436ace72007-07-24 15:42:08 +0530479 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600480 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600481 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600482
483 /* Check/log IOC log info
484 */
485 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
486 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
487 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
488 if (ioc->bus_type == FC)
489 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700490 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700491 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600492 else if (ioc->bus_type == SAS)
493 mpt_sas_log_info(ioc, log_info);
494 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600495
Eric Moorec6c727a2007-01-29 09:44:54 -0700496 if (ioc_stat & MPI_IOCSTATUS_MASK)
497 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600498
499 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530500 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600501 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600502 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700503 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600504 freeme = 0;
505 goto out;
506 }
507
508 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
509
510 out:
511 /* Flush (non-TURBO) reply with a WRITE! */
512 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
513
514 if (freeme)
515 mpt_free_msg_frame(ioc, mf);
516 mb();
517}
518
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800520/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
522 * @irq: irq number (not used)
523 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 *
525 * This routine is registered via the request_irq() kernel API call,
526 * and handles all interrupts generated from a specific MPT adapter
527 * (also referred to as a IO Controller or IOC).
528 * This routine must clear the interrupt from the adapter and does
529 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200530 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 *
532 * This routine handles register-level access of the adapter but
533 * dispatches (calls) a protocol-specific callback routine to handle
534 * the protocol-specific details of the MPT request completion.
535 */
536static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100537mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600539 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600540 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
541
542 if (pa == 0xFFFFFFFF)
543 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
545 /*
546 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600548 do {
549 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600550 mpt_reply(ioc, pa);
551 else
552 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600553 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
554 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
556 return IRQ_HANDLED;
557}
558
559/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800560/**
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530561 * mptbase_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 * @ioc: Pointer to MPT_ADAPTER structure
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530563 * @req: Pointer to original MPT request frame
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
565 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800566 * MPT base driver's callback routine; all base driver
567 * "internal" request/reply processing is routed here.
568 * Currently used for EventNotification and EventAck handling.
569 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200570 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 * should be freed, or 0 if it shouldn't.
572 */
573static int
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530574mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530576 EventNotificationReply_t *pEventReply;
577 u8 event;
578 int evHandlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 int freereq = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530581 switch (reply->u.hdr.Function) {
582 case MPI_FUNCTION_EVENT_NOTIFICATION:
583 pEventReply = (EventNotificationReply_t *)reply;
584 evHandlers = 0;
585 ProcessEventNotification(ioc, pEventReply, &evHandlers);
586 event = le32_to_cpu(pEventReply->Event) & 0xFF;
587 if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 freereq = 0;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530589 if (event != MPI_EVENT_EVENT_CHANGE)
590 break;
591 case MPI_FUNCTION_CONFIG:
592 case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
593 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
594 if (reply) {
595 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
596 memcpy(ioc->mptbase_cmds.reply, reply,
597 min(MPT_DEFAULT_FRAME_SIZE,
598 4 * reply->u.reply.MsgLength));
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200599 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530600 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
601 ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
602 complete(&ioc->mptbase_cmds.done);
603 } else
604 freereq = 0;
605 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF)
606 freereq = 1;
607 break;
608 case MPI_FUNCTION_EVENT_ACK:
609 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
610 "EventAck reply received\n", ioc->name));
611 break;
612 default:
613 printk(MYIOC_s_ERR_FMT
614 "Unexpected msg function (=%02Xh) reply received!\n",
615 ioc->name, reply->u.hdr.Function);
616 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
618
619 /*
620 * Conditionally tell caller to free the original
621 * EventNotification/EventAck/unexpected request frame!
622 */
623 return freereq;
624}
625
626/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
627/**
628 * mpt_register - Register protocol-specific main callback handler.
629 * @cbfunc: callback function pointer
630 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
631 *
632 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800633 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 * protocol-specific driver must do this before it will be able to
635 * use any IOC resources, such as obtaining request frames.
636 *
637 * NOTES: The SCSI protocol driver currently calls this routine thrice
638 * in order to register separate callbacks; one for "normal" SCSI IO;
639 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
640 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530641 * Returns u8 valued "handle" in the range (and S.O.D. order)
642 * {N,...,7,6,5,...,1} if successful.
643 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
644 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530646u8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
648{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530649 u8 cb_idx;
650 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
652 /*
653 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
654 * (slot/handle 0 is reserved!)
655 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530656 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
657 if (MptCallbacks[cb_idx] == NULL) {
658 MptCallbacks[cb_idx] = cbfunc;
659 MptDriverClass[cb_idx] = dclass;
660 MptEvHandlers[cb_idx] = NULL;
661 last_drv_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 break;
663 }
664 }
665
666 return last_drv_idx;
667}
668
669/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
670/**
671 * mpt_deregister - Deregister a protocol drivers resources.
672 * @cb_idx: previously registered callback handle
673 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800674 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 * module is unloaded.
676 */
677void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530678mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600680 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 MptCallbacks[cb_idx] = NULL;
682 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
683 MptEvHandlers[cb_idx] = NULL;
684
685 last_drv_idx++;
686 }
687}
688
689/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
690/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800691 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 * @cb_idx: previously registered (via mpt_register) callback handle
693 * @ev_cbfunc: callback function
694 *
695 * This routine can be called by one or more protocol-specific drivers
696 * if/when they choose to be notified of MPT events.
697 *
698 * Returns 0 for success.
699 */
700int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530701mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600703 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 return -1;
705
706 MptEvHandlers[cb_idx] = ev_cbfunc;
707 return 0;
708}
709
710/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
711/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800712 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 * @cb_idx: previously registered callback handle
714 *
715 * Each protocol-specific driver should call this routine
716 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800717 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 */
719void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530720mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600722 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 return;
724
725 MptEvHandlers[cb_idx] = NULL;
726}
727
728/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
729/**
730 * mpt_reset_register - Register protocol-specific IOC reset handler.
731 * @cb_idx: previously registered (via mpt_register) callback handle
732 * @reset_func: reset function
733 *
734 * This routine can be called by one or more protocol-specific drivers
735 * if/when they choose to be notified of IOC resets.
736 *
737 * Returns 0 for success.
738 */
739int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530740mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530742 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 return -1;
744
745 MptResetHandlers[cb_idx] = reset_func;
746 return 0;
747}
748
749/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
750/**
751 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
752 * @cb_idx: previously registered callback handle
753 *
754 * Each protocol-specific driver should call this routine
755 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800756 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 */
758void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530759mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530761 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return;
763
764 MptResetHandlers[cb_idx] = NULL;
765}
766
767/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
768/**
769 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800770 * @dd_cbfunc: driver callbacks struct
771 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 */
773int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530774mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
776 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600777 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Eric Moore8d6d83e2007-09-14 18:47:40 -0600779 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400780 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
782 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
783
784 /* call per pci device probe entry point */
785 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600786 id = ioc->pcidev->driver ?
787 ioc->pcidev->driver->id_table : NULL;
788 if (dd_cbfunc->probe)
789 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 }
791
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400792 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793}
794
795/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
796/**
797 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800798 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 */
800void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530801mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802{
803 struct mpt_pci_driver *dd_cbfunc;
804 MPT_ADAPTER *ioc;
805
Eric Moore8d6d83e2007-09-14 18:47:40 -0600806 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 return;
808
809 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
810
811 list_for_each_entry(ioc, &ioc_list, list) {
812 if (dd_cbfunc->remove)
813 dd_cbfunc->remove(ioc->pcidev);
814 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200815
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 MptDeviceDriverHandlers[cb_idx] = NULL;
817}
818
819
820/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
821/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800822 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530823 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 * @ioc: Pointer to MPT adapter structure
825 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800826 * Obtain an MPT request frame from the pool (of 1024) that are
827 * allocated per MPT adapter.
828 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 * Returns pointer to a MPT request frame or %NULL if none are available
830 * or IOC is not active.
831 */
832MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530833mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834{
835 MPT_FRAME_HDR *mf;
836 unsigned long flags;
837 u16 req_idx; /* Request index */
838
839 /* validate handle and ioc identifier */
840
841#ifdef MFCNT
842 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600843 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
844 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845#endif
846
847 /* If interrupts are not attached, do not return a request frame */
848 if (!ioc->active)
849 return NULL;
850
851 spin_lock_irqsave(&ioc->FreeQlock, flags);
852 if (!list_empty(&ioc->FreeQ)) {
853 int req_offset;
854
855 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
856 u.frame.linkage.list);
857 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200858 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530859 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
861 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500862 req_idx = req_offset / ioc->req_sz;
863 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600865 /* Default, will be changed if necessary in SG generation */
866 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867#ifdef MFCNT
868 ioc->mfcnt++;
869#endif
870 }
871 else
872 mf = NULL;
873 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
874
875#ifdef MFCNT
876 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600877 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
878 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
879 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 mfcounter++;
881 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600882 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
883 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884#endif
885
Eric Moore29dd3602007-09-14 18:46:51 -0600886 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
887 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 return mf;
889}
890
891/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
892/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800893 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530894 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 * @ioc: Pointer to MPT adapter structure
896 * @mf: Pointer to MPT request frame
897 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800898 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 * specific MPT adapter.
900 */
901void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530902mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903{
904 u32 mf_dma_addr;
905 int req_offset;
906 u16 req_idx; /* Request index */
907
908 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530909 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
911 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500912 req_idx = req_offset / ioc->req_sz;
913 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
915
Prakash, Sathya436ace72007-07-24 15:42:08 +0530916 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200918 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600919 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
920 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
921 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
923}
924
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530925/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800926 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530927 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530928 * @ioc: Pointer to MPT adapter structure
929 * @mf: Pointer to MPT request frame
930 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800931 * Send a protocol-specific MPT request frame to an IOC using
932 * hi-priority request queue.
933 *
934 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530935 * specific MPT adapter.
936 **/
937void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530938mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530939{
940 u32 mf_dma_addr;
941 int req_offset;
942 u16 req_idx; /* Request index */
943
944 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530945 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530946 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
947 req_idx = req_offset / ioc->req_sz;
948 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
949 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
950
951 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
952
953 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
954 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
955 ioc->name, mf_dma_addr, req_idx));
956 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
957}
958
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
960/**
961 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 * @ioc: Pointer to MPT adapter structure
963 * @mf: Pointer to MPT request frame
964 *
965 * This routine places a MPT request frame back on the MPT adapter's
966 * FreeQ.
967 */
968void
969mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
970{
971 unsigned long flags;
972
973 /* Put Request back on FreeQ! */
974 spin_lock_irqsave(&ioc->FreeQlock, flags);
Kashyap, Desai2f187862009-05-29 16:52:37 +0530975 if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf)
976 goto out;
977 /* signature to know if this mf is freed */
978 mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
980#ifdef MFCNT
981 ioc->mfcnt--;
982#endif
Kashyap, Desai2f187862009-05-29 16:52:37 +0530983 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
985}
986
987/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
988/**
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530989 * mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 * @pAddr: virtual address for SGE
991 * @flagslength: SGE flags and data transfer length
992 * @dma_addr: Physical address
993 *
994 * This routine places a MPT request frame back on the MPT adapter's
995 * FreeQ.
996 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530997static void
998mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999{
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301000 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
1001 pSge->FlagsLength = cpu_to_le32(flagslength);
1002 pSge->Address = cpu_to_le32(dma_addr);
1003}
1004
1005/**
1006 * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
1007 * @pAddr: virtual address for SGE
1008 * @flagslength: SGE flags and data transfer length
1009 * @dma_addr: Physical address
1010 *
1011 * This routine places a MPT request frame back on the MPT adapter's
1012 * FreeQ.
1013 **/
1014static void
1015mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1016{
1017 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1018 pSge->Address.Low = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301019 (lower_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301020 pSge->Address.High = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301021 (upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301022 pSge->FlagsLength = cpu_to_le32
1023 ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1024}
1025
1026/**
Randy Dunlap9cf46a32009-06-13 19:37:18 -07001027 * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr (1078 workaround).
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301028 * @pAddr: virtual address for SGE
1029 * @flagslength: SGE flags and data transfer length
1030 * @dma_addr: Physical address
1031 *
1032 * This routine places a MPT request frame back on the MPT adapter's
1033 * FreeQ.
1034 **/
1035static void
1036mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1037{
1038 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1039 u32 tmp;
1040
1041 pSge->Address.Low = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301042 (lower_32_bits(dma_addr));
1043 tmp = (u32)(upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301044
1045 /*
1046 * 1078 errata workaround for the 36GB limitation
1047 */
1048 if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {
1049 flagslength |=
1050 MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
1051 tmp |= (1<<31);
1052 if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
1053 printk(KERN_DEBUG "1078 P0M2 addressing for "
1054 "addr = 0x%llx len = %d\n",
1055 (unsigned long long)dma_addr,
1056 MPI_SGE_LENGTH(flagslength));
1057 }
1058
1059 pSge->Address.High = cpu_to_le32(tmp);
1060 pSge->FlagsLength = cpu_to_le32(
1061 (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1062}
1063
1064/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1065/**
1066 * mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
1067 * @pAddr: virtual address for SGE
1068 * @next: nextChainOffset value (u32's)
1069 * @length: length of next SGL segment
1070 * @dma_addr: Physical address
1071 *
1072 */
1073static void
1074mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1075{
1076 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
1077 pChain->Length = cpu_to_le16(length);
1078 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
1079 pChain->NextChainOffset = next;
1080 pChain->Address = cpu_to_le32(dma_addr);
1081}
1082
1083/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1084/**
1085 * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
1086 * @pAddr: virtual address for SGE
1087 * @next: nextChainOffset value (u32's)
1088 * @length: length of next SGL segment
1089 * @dma_addr: Physical address
1090 *
1091 */
1092static void
1093mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1094{
1095 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 u32 tmp = dma_addr & 0xFFFFFFFF;
1097
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301098 pChain->Length = cpu_to_le16(length);
1099 pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
1100 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301102 pChain->NextChainOffset = next;
1103
1104 pChain->Address.Low = cpu_to_le32(tmp);
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301105 tmp = (u32)(upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301106 pChain->Address.High = cpu_to_le32(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107}
1108
1109/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1110/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001111 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301112 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 * @ioc: Pointer to MPT adapter structure
1114 * @reqBytes: Size of the request in bytes
1115 * @req: Pointer to MPT request frame
1116 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1117 *
1118 * This routine is used exclusively to send MptScsiTaskMgmt
1119 * requests since they are required to be sent via doorbell handshake.
1120 *
1121 * NOTE: It is the callers responsibility to byte-swap fields in the
1122 * request which are greater than 1 byte in size.
1123 *
1124 * Returns 0 for success, non-zero for failure.
1125 */
1126int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301127mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128{
Eric Moorecd2c6192007-01-29 09:47:47 -07001129 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 u8 *req_as_bytes;
1131 int ii;
1132
1133 /* State is known to be good upon entering
1134 * this function so issue the bus reset
1135 * request.
1136 */
1137
1138 /*
1139 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1140 * setting cb_idx/req_idx. But ONLY if this request
1141 * is in proper (pre-alloc'd) request buffer range...
1142 */
1143 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1144 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1145 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1146 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301147 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 }
1149
1150 /* Make sure there are no doorbells */
1151 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001152
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1154 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1155 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1156
1157 /* Wait for IOC doorbell int */
1158 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1159 return ii;
1160 }
1161
1162 /* Read doorbell and check for active bit */
1163 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1164 return -5;
1165
Eric Moore29dd3602007-09-14 18:46:51 -06001166 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001167 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
1169 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1170
1171 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1172 return -2;
1173 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001174
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 /* Send request via doorbell handshake */
1176 req_as_bytes = (u8 *) req;
1177 for (ii = 0; ii < reqBytes/4; ii++) {
1178 u32 word;
1179
1180 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1181 (req_as_bytes[(ii*4) + 1] << 8) |
1182 (req_as_bytes[(ii*4) + 2] << 16) |
1183 (req_as_bytes[(ii*4) + 3] << 24));
1184 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1185 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1186 r = -3;
1187 break;
1188 }
1189 }
1190
1191 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1192 r = 0;
1193 else
1194 r = -4;
1195
1196 /* Make sure there are no doorbells */
1197 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001198
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 return r;
1200}
1201
1202/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1203/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001204 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001205 * @ioc: Pointer to MPT adapter structure
1206 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001207 * @sleepFlag: Specifies whether the process can sleep
1208 *
1209 * Provides mechanism for the host driver to control the IOC's
1210 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001211 *
1212 * Access Control Value - bits[15:12]
1213 * 0h Reserved
1214 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1215 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1216 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1217 *
1218 * Returns 0 for success, non-zero for failure.
1219 */
1220
1221static int
1222mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1223{
1224 int r = 0;
1225
1226 /* return if in use */
1227 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1228 & MPI_DOORBELL_ACTIVE)
1229 return -1;
1230
1231 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1232
1233 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1234 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1235 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1236 (access_control_value<<12)));
1237
1238 /* Wait for IOC to clear Doorbell Status bit */
1239 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1240 return -2;
1241 }else
1242 return 0;
1243}
1244
1245/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1246/**
1247 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001248 * @ioc: Pointer to pointer to IOC adapter
1249 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001250 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001251 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001252 * Returns 0 for success, non-zero for failure.
1253 */
1254static int
1255mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1256{
1257 char *psge;
1258 int flags_length;
1259 u32 host_page_buffer_sz=0;
1260
1261 if(!ioc->HostPageBuffer) {
1262
1263 host_page_buffer_sz =
1264 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1265
1266 if(!host_page_buffer_sz)
1267 return 0; /* fw doesn't need any host buffers */
1268
1269 /* spin till we get enough memory */
1270 while(host_page_buffer_sz > 0) {
1271
1272 if((ioc->HostPageBuffer = pci_alloc_consistent(
1273 ioc->pcidev,
1274 host_page_buffer_sz,
1275 &ioc->HostPageBuffer_dma)) != NULL) {
1276
Prakash, Sathya436ace72007-07-24 15:42:08 +05301277 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001278 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001279 ioc->name, ioc->HostPageBuffer,
1280 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001281 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001282 ioc->alloc_total += host_page_buffer_sz;
1283 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1284 break;
1285 }
1286
1287 host_page_buffer_sz -= (4*1024);
1288 }
1289 }
1290
1291 if(!ioc->HostPageBuffer) {
1292 printk(MYIOC_s_ERR_FMT
1293 "Failed to alloc memory for host_page_buffer!\n",
1294 ioc->name);
1295 return -999;
1296 }
1297
1298 psge = (char *)&ioc_init->HostPageBufferSGE;
1299 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1300 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001301 MPI_SGE_FLAGS_HOST_TO_IOC |
1302 MPI_SGE_FLAGS_END_OF_BUFFER;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001303 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1304 flags_length |= ioc->HostPageBuffer_sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301305 ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001306 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1307
1308return 0;
1309}
1310
1311/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1312/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001313 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 * @iocid: IOC unique identifier (integer)
1315 * @iocpp: Pointer to pointer to IOC adapter
1316 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001317 * Given a unique IOC identifier, set pointer to the associated MPT
1318 * adapter structure.
1319 *
1320 * Returns iocid and sets iocpp if iocid is found.
1321 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 */
1323int
1324mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1325{
1326 MPT_ADAPTER *ioc;
1327
1328 list_for_each_entry(ioc,&ioc_list,list) {
1329 if (ioc->id == iocid) {
1330 *iocpp =ioc;
1331 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001334
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 *iocpp = NULL;
1336 return -1;
1337}
1338
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301339/**
1340 * mpt_get_product_name - returns product string
1341 * @vendor: pci vendor id
1342 * @device: pci device id
1343 * @revision: pci revision id
1344 * @prod_name: string returned
1345 *
1346 * Returns product string displayed when driver loads,
1347 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1348 *
1349 **/
1350static void
1351mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1352{
1353 char *product_str = NULL;
1354
1355 if (vendor == PCI_VENDOR_ID_BROCADE) {
1356 switch (device)
1357 {
1358 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1359 switch (revision)
1360 {
1361 case 0x00:
1362 product_str = "BRE040 A0";
1363 break;
1364 case 0x01:
1365 product_str = "BRE040 A1";
1366 break;
1367 default:
1368 product_str = "BRE040";
1369 break;
1370 }
1371 break;
1372 }
1373 goto out;
1374 }
1375
1376 switch (device)
1377 {
1378 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1379 product_str = "LSIFC909 B1";
1380 break;
1381 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1382 product_str = "LSIFC919 B0";
1383 break;
1384 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1385 product_str = "LSIFC929 B0";
1386 break;
1387 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1388 if (revision < 0x80)
1389 product_str = "LSIFC919X A0";
1390 else
1391 product_str = "LSIFC919XL A1";
1392 break;
1393 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1394 if (revision < 0x80)
1395 product_str = "LSIFC929X A0";
1396 else
1397 product_str = "LSIFC929XL A1";
1398 break;
1399 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1400 product_str = "LSIFC939X A1";
1401 break;
1402 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1403 product_str = "LSIFC949X A1";
1404 break;
1405 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1406 switch (revision)
1407 {
1408 case 0x00:
1409 product_str = "LSIFC949E A0";
1410 break;
1411 case 0x01:
1412 product_str = "LSIFC949E A1";
1413 break;
1414 default:
1415 product_str = "LSIFC949E";
1416 break;
1417 }
1418 break;
1419 case MPI_MANUFACTPAGE_DEVID_53C1030:
1420 switch (revision)
1421 {
1422 case 0x00:
1423 product_str = "LSI53C1030 A0";
1424 break;
1425 case 0x01:
1426 product_str = "LSI53C1030 B0";
1427 break;
1428 case 0x03:
1429 product_str = "LSI53C1030 B1";
1430 break;
1431 case 0x07:
1432 product_str = "LSI53C1030 B2";
1433 break;
1434 case 0x08:
1435 product_str = "LSI53C1030 C0";
1436 break;
1437 case 0x80:
1438 product_str = "LSI53C1030T A0";
1439 break;
1440 case 0x83:
1441 product_str = "LSI53C1030T A2";
1442 break;
1443 case 0x87:
1444 product_str = "LSI53C1030T A3";
1445 break;
1446 case 0xc1:
1447 product_str = "LSI53C1020A A1";
1448 break;
1449 default:
1450 product_str = "LSI53C1030";
1451 break;
1452 }
1453 break;
1454 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1455 switch (revision)
1456 {
1457 case 0x03:
1458 product_str = "LSI53C1035 A2";
1459 break;
1460 case 0x04:
1461 product_str = "LSI53C1035 B0";
1462 break;
1463 default:
1464 product_str = "LSI53C1035";
1465 break;
1466 }
1467 break;
1468 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1469 switch (revision)
1470 {
1471 case 0x00:
1472 product_str = "LSISAS1064 A1";
1473 break;
1474 case 0x01:
1475 product_str = "LSISAS1064 A2";
1476 break;
1477 case 0x02:
1478 product_str = "LSISAS1064 A3";
1479 break;
1480 case 0x03:
1481 product_str = "LSISAS1064 A4";
1482 break;
1483 default:
1484 product_str = "LSISAS1064";
1485 break;
1486 }
1487 break;
1488 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1489 switch (revision)
1490 {
1491 case 0x00:
1492 product_str = "LSISAS1064E A0";
1493 break;
1494 case 0x01:
1495 product_str = "LSISAS1064E B0";
1496 break;
1497 case 0x02:
1498 product_str = "LSISAS1064E B1";
1499 break;
1500 case 0x04:
1501 product_str = "LSISAS1064E B2";
1502 break;
1503 case 0x08:
1504 product_str = "LSISAS1064E B3";
1505 break;
1506 default:
1507 product_str = "LSISAS1064E";
1508 break;
1509 }
1510 break;
1511 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1512 switch (revision)
1513 {
1514 case 0x00:
1515 product_str = "LSISAS1068 A0";
1516 break;
1517 case 0x01:
1518 product_str = "LSISAS1068 B0";
1519 break;
1520 case 0x02:
1521 product_str = "LSISAS1068 B1";
1522 break;
1523 default:
1524 product_str = "LSISAS1068";
1525 break;
1526 }
1527 break;
1528 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1529 switch (revision)
1530 {
1531 case 0x00:
1532 product_str = "LSISAS1068E A0";
1533 break;
1534 case 0x01:
1535 product_str = "LSISAS1068E B0";
1536 break;
1537 case 0x02:
1538 product_str = "LSISAS1068E B1";
1539 break;
1540 case 0x04:
1541 product_str = "LSISAS1068E B2";
1542 break;
1543 case 0x08:
1544 product_str = "LSISAS1068E B3";
1545 break;
1546 default:
1547 product_str = "LSISAS1068E";
1548 break;
1549 }
1550 break;
1551 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1552 switch (revision)
1553 {
1554 case 0x00:
1555 product_str = "LSISAS1078 A0";
1556 break;
1557 case 0x01:
1558 product_str = "LSISAS1078 B0";
1559 break;
1560 case 0x02:
1561 product_str = "LSISAS1078 C0";
1562 break;
1563 case 0x03:
1564 product_str = "LSISAS1078 C1";
1565 break;
1566 case 0x04:
1567 product_str = "LSISAS1078 C2";
1568 break;
1569 default:
1570 product_str = "LSISAS1078";
1571 break;
1572 }
1573 break;
1574 }
1575
1576 out:
1577 if (product_str)
1578 sprintf(prod_name, "%s", product_str);
1579}
1580
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301581/**
1582 * mpt_mapresources - map in memory mapped io
1583 * @ioc: Pointer to pointer to IOC adapter
1584 *
1585 **/
1586static int
1587mpt_mapresources(MPT_ADAPTER *ioc)
1588{
1589 u8 __iomem *mem;
1590 int ii;
Pravin Bathijae46b63b2009-12-02 17:51:46 -08001591 resource_size_t mem_phys;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301592 unsigned long port;
1593 u32 msize;
1594 u32 psize;
1595 u8 revision;
1596 int r = -ENODEV;
1597 struct pci_dev *pdev;
1598
1599 pdev = ioc->pcidev;
1600 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1601 if (pci_enable_device_mem(pdev)) {
1602 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1603 "failed\n", ioc->name);
1604 return r;
1605 }
1606 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1607 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1608 "MEM failed\n", ioc->name);
1609 return r;
1610 }
1611
1612 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1613
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301614 if (sizeof(dma_addr_t) > 4) {
1615 const uint64_t required_mask = dma_get_required_mask
1616 (&pdev->dev);
1617 if (required_mask > DMA_BIT_MASK(32)
1618 && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
1619 && !pci_set_consistent_dma_mask(pdev,
1620 DMA_BIT_MASK(64))) {
1621 ioc->dma_mask = DMA_BIT_MASK(64);
1622 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1623 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1624 ioc->name));
1625 } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1626 && !pci_set_consistent_dma_mask(pdev,
1627 DMA_BIT_MASK(32))) {
1628 ioc->dma_mask = DMA_BIT_MASK(32);
1629 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1630 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1631 ioc->name));
1632 } else {
1633 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1634 ioc->name, pci_name(pdev));
1635 return r;
1636 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301637 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301638 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1639 && !pci_set_consistent_dma_mask(pdev,
1640 DMA_BIT_MASK(32))) {
1641 ioc->dma_mask = DMA_BIT_MASK(32);
1642 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1643 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1644 ioc->name));
1645 } else {
1646 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1647 ioc->name, pci_name(pdev));
1648 return r;
1649 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301650 }
1651
1652 mem_phys = msize = 0;
1653 port = psize = 0;
1654 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1655 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1656 if (psize)
1657 continue;
1658 /* Get I/O space! */
1659 port = pci_resource_start(pdev, ii);
1660 psize = pci_resource_len(pdev, ii);
1661 } else {
1662 if (msize)
1663 continue;
1664 /* Get memmap */
1665 mem_phys = pci_resource_start(pdev, ii);
1666 msize = pci_resource_len(pdev, ii);
1667 }
1668 }
1669 ioc->mem_size = msize;
1670
1671 mem = NULL;
1672 /* Get logical ptr for PciMem0 space */
1673 /*mem = ioremap(mem_phys, msize);*/
1674 mem = ioremap(mem_phys, msize);
1675 if (mem == NULL) {
1676 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1677 " memory!\n", ioc->name);
1678 return -EINVAL;
1679 }
1680 ioc->memmap = mem;
Pravin Bathijae46b63b2009-12-02 17:51:46 -08001681 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %llx\n",
1682 ioc->name, mem, (unsigned long long)mem_phys));
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301683
1684 ioc->mem_phys = mem_phys;
1685 ioc->chip = (SYSIF_REGS __iomem *)mem;
1686
1687 /* Save Port IO values in case we need to do downloadboot */
1688 ioc->pio_mem_phys = port;
1689 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1690
1691 return 0;
1692}
1693
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001695/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001696 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001698 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 *
1700 * This routine performs all the steps necessary to bring the IOC of
1701 * a MPT adapter to a OPERATIONAL state. This includes registering
1702 * memory regions, registering the interrupt, and allocating request
1703 * and reply memory pools.
1704 *
1705 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1706 * MPT adapter.
1707 *
1708 * Returns 0 for success, non-zero for failure.
1709 *
1710 * TODO: Add support for polled controllers
1711 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001712int
1713mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714{
1715 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301716 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 u8 revision;
1719 u8 pcixcmd;
1720 static int mpt_ids = 0;
1721#ifdef CONFIG_PROC_FS
1722 struct proc_dir_entry *dent, *ent;
1723#endif
1724
Jesper Juhl56876192007-08-10 14:50:51 -07001725 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1726 if (ioc == NULL) {
1727 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1728 return -ENOMEM;
1729 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301730
Eric Moore29dd3602007-09-14 18:46:51 -06001731 ioc->id = mpt_ids++;
1732 sprintf(ioc->name, "ioc%d", ioc->id);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301733 dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Jesper Juhl56876192007-08-10 14:50:51 -07001734
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301735 /*
1736 * set initial debug level
1737 * (refer to mptdebug.h)
1738 *
1739 */
1740 ioc->debug_level = mpt_debug_level;
1741 if (mpt_debug_level)
1742 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301743
Eric Moore29dd3602007-09-14 18:46:51 -06001744 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001745
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301746 ioc->pcidev = pdev;
1747 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001748 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 return r;
1750 }
1751
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301752 /*
1753 * Setting up proper handlers for scatter gather handling
1754 */
1755 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
1756 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
1757 ioc->add_sge = &mpt_add_sge_64bit_1078;
1758 else
1759 ioc->add_sge = &mpt_add_sge_64bit;
1760 ioc->add_chain = &mpt_add_chain_64bit;
1761 ioc->sg_addr_size = 8;
1762 } else {
1763 ioc->add_sge = &mpt_add_sge;
1764 ioc->add_chain = &mpt_add_chain;
1765 ioc->sg_addr_size = 4;
1766 }
1767 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
1768
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 ioc->alloc_total = sizeof(MPT_ADAPTER);
1770 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1771 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001772
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301774 spin_lock_init(&ioc->taskmgmt_lock);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05301775 mutex_init(&ioc->internal_cmds.mutex);
1776 init_completion(&ioc->internal_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301777 mutex_init(&ioc->mptbase_cmds.mutex);
1778 init_completion(&ioc->mptbase_cmds.done);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301779 mutex_init(&ioc->taskmgmt_cmds.mutex);
1780 init_completion(&ioc->taskmgmt_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301781
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 /* Initialize the event logging.
1783 */
1784 ioc->eventTypes = 0; /* None */
1785 ioc->eventContext = 0;
1786 ioc->eventLogSize = 0;
1787 ioc->events = NULL;
1788
1789#ifdef MFCNT
1790 ioc->mfcnt = 0;
1791#endif
1792
Kashyap, Desai2f187862009-05-29 16:52:37 +05301793 ioc->sh = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 ioc->cached_fw = NULL;
1795
1796 /* Initilize SCSI Config Data structure
1797 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001798 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799
Michael Reed05e8ec12006-01-13 14:31:54 -06001800 /* Initialize the fc rport list head.
1801 */
1802 INIT_LIST_HEAD(&ioc->fc_rports);
1803
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 /* Find lookup slot. */
1805 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001806
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301807
1808 /* Initialize workqueue */
1809 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301810
Kashyap, Desai2f187862009-05-29 16:52:37 +05301811 snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN,
Kay Sieversaab0de22008-05-02 06:02:41 +02001812 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301813 ioc->reset_work_q =
1814 create_singlethread_workqueue(ioc->reset_work_q_name);
1815 if (!ioc->reset_work_q) {
1816 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1817 ioc->name);
1818 pci_release_selected_regions(pdev, ioc->bars);
1819 kfree(ioc);
1820 return -ENOMEM;
1821 }
1822
Eric Moore29dd3602007-09-14 18:46:51 -06001823 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1824 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301826 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1827 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1828
1829 switch (pdev->device)
1830 {
1831 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1832 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1833 ioc->errata_flag_1064 = 1;
1834 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1835 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1836 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1837 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301839 break;
1840
1841 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 /* 929X Chip Fix. Set Split transactions level
1844 * for PCIX. Set MOST bits to zero.
1845 */
1846 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1847 pcixcmd &= 0x8F;
1848 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1849 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 /* 929XL Chip Fix. Set MMRBC to 0x08.
1851 */
1852 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1853 pcixcmd |= 0x08;
1854 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1855 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301857 break;
1858
1859 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 /* 919X Chip Fix. Set Split transactions level
1861 * for PCIX. Set MOST bits to zero.
1862 */
1863 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1864 pcixcmd &= 0x8F;
1865 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001866 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301867 break;
1868
1869 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 /* 1030 Chip Fix. Disable Split transactions
1871 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1872 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 if (revision < C0_1030) {
1874 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1875 pcixcmd &= 0x8F;
1876 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1877 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301878
1879 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001880 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301881 break;
1882
1883 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1884 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001885 ioc->errata_flag_1064 = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301886 ioc->bus_type = SAS;
1887 break;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301888
1889 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1890 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1891 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001892 ioc->bus_type = SAS;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301893 break;
Eric Moore87cf8982006-06-27 16:09:26 -06001894 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301896
Kashyap, Desaie3829682009-01-08 14:27:16 +05301897 switch (ioc->bus_type) {
1898
1899 case SAS:
1900 ioc->msi_enable = mpt_msi_enable_sas;
1901 break;
1902
1903 case SPI:
1904 ioc->msi_enable = mpt_msi_enable_spi;
1905 break;
1906
1907 case FC:
1908 ioc->msi_enable = mpt_msi_enable_fc;
1909 break;
1910
1911 default:
1912 ioc->msi_enable = 0;
1913 break;
1914 }
Kashyap, Desai8ce13de2010-06-17 14:35:46 +05301915
1916 ioc->fw_events_off = 1;
1917
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001918 if (ioc->errata_flag_1064)
1919 pci_disable_io_access(pdev);
1920
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 spin_lock_init(&ioc->FreeQlock);
1922
1923 /* Disable all! */
1924 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1925 ioc->active = 0;
1926 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1927
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301928 /* Set IOC ptr in the pcidev's driver data. */
1929 pci_set_drvdata(ioc->pcidev, ioc);
1930
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 /* Set lookup ptr. */
1932 list_add_tail(&ioc->list, &ioc_list);
1933
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001934 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 */
1936 mpt_detect_bound_ports(ioc, pdev);
1937
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301938 INIT_LIST_HEAD(&ioc->fw_event_list);
1939 spin_lock_init(&ioc->fw_event_lock);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301940 snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301941 ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
1942
James Bottomleyc92f2222006-03-01 09:02:49 -06001943 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1944 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001945 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1946 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001947
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001949 if (ioc->alt_ioc)
1950 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301951 iounmap(ioc->memmap);
1952 if (r != -5)
1953 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301954
1955 destroy_workqueue(ioc->reset_work_q);
1956 ioc->reset_work_q = NULL;
1957
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 kfree(ioc);
1959 pci_set_drvdata(pdev, NULL);
1960 return r;
1961 }
1962
1963 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001964 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301965 if(MptDeviceDriverHandlers[cb_idx] &&
1966 MptDeviceDriverHandlers[cb_idx]->probe) {
1967 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 }
1969 }
1970
1971#ifdef CONFIG_PROC_FS
1972 /*
1973 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1974 */
1975 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1976 if (dent) {
1977 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1978 if (ent) {
1979 ent->read_proc = procmpt_iocinfo_read;
1980 ent->data = ioc;
1981 }
1982 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1983 if (ent) {
1984 ent->read_proc = procmpt_summary_read;
1985 ent->data = ioc;
1986 }
1987 }
1988#endif
1989
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301990 if (!ioc->alt_ioc)
1991 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1992 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1993
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 return 0;
1995}
1996
1997/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001998/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001999 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 */
2002
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002003void
2004mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005{
2006 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2007 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302008 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302009 unsigned long flags;
2010 struct workqueue_struct *wq;
2011
2012 /*
2013 * Stop polling ioc for fault condition
2014 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302015 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302016 wq = ioc->reset_work_q;
2017 ioc->reset_work_q = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302018 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302019 cancel_delayed_work(&ioc->fault_reset_work);
2020 destroy_workqueue(wq);
2021
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05302022 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2023 wq = ioc->fw_event_q;
2024 ioc->fw_event_q = NULL;
2025 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2026 destroy_workqueue(wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027
2028 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2029 remove_proc_entry(pname, NULL);
2030 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2031 remove_proc_entry(pname, NULL);
2032 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2033 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002034
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002036 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302037 if(MptDeviceDriverHandlers[cb_idx] &&
2038 MptDeviceDriverHandlers[cb_idx]->remove) {
2039 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 }
2041 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002042
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 /* Disable interrupts! */
2044 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2045
2046 ioc->active = 0;
2047 synchronize_irq(pdev->irq);
2048
2049 /* Clear any lingering interrupt */
2050 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2051
2052 CHIPREG_READ32(&ioc->chip->IntStatus);
2053
2054 mpt_adapter_dispose(ioc);
2055
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056}
2057
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058/**************************************************************************
2059 * Power Management
2060 */
2061#ifdef CONFIG_PM
2062/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002063/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002064 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002065 * @pdev: Pointer to pci_dev structure
2066 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002068int
2069mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070{
2071 u32 device_state;
2072 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302074 device_state = pci_choose_state(pdev, state);
2075 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2076 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2077 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078
2079 /* put ioc into READY_STATE */
2080 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2081 printk(MYIOC_s_ERR_FMT
2082 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2083 }
2084
2085 /* disable interrupts */
2086 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2087 ioc->active = 0;
2088
2089 /* Clear any lingering interrupt */
2090 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2091
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302092 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002093 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302094 pci_disable_msi(ioc->pcidev);
2095 ioc->pci_irq = -1;
2096 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302098 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 return 0;
2101}
2102
2103/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002104/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002105 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002106 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002108int
2109mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110{
2111 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2112 u32 device_state = pdev->current_state;
2113 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302114 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002115
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302116 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2117 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2118 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302120 pci_set_power_state(pdev, PCI_D0);
2121 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302123 ioc->pcidev = pdev;
2124 err = mpt_mapresources(ioc);
2125 if (err)
2126 return err;
2127
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302128 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2129 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2130 ioc->add_sge = &mpt_add_sge_64bit_1078;
2131 else
2132 ioc->add_sge = &mpt_add_sge_64bit;
2133 ioc->add_chain = &mpt_add_chain_64bit;
2134 ioc->sg_addr_size = 8;
2135 } else {
2136
2137 ioc->add_sge = &mpt_add_sge;
2138 ioc->add_chain = &mpt_add_chain;
2139 ioc->sg_addr_size = 4;
2140 }
2141 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2142
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302143 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2144 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2145 CHIPREG_READ32(&ioc->chip->Doorbell));
2146
2147 /*
2148 * Errata workaround for SAS pci express:
2149 * Upon returning to the D0 state, the contents of the doorbell will be
2150 * stale data, and this will incorrectly signal to the host driver that
2151 * the firmware is ready to process mpt commands. The workaround is
2152 * to issue a diagnostic reset.
2153 */
2154 if (ioc->bus_type == SAS && (pdev->device ==
2155 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2156 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2157 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2158 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2159 ioc->name);
2160 goto out;
2161 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302162 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163
2164 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302165 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2166 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2167 CAN_SLEEP);
2168 if (recovery_state != 0)
2169 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2170 "error:[%x]\n", ioc->name, recovery_state);
2171 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302173 "pci-resume: success\n", ioc->name);
2174 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302176
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177}
2178#endif
2179
James Bottomley4ff42a62006-05-17 18:06:52 -05002180static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302181mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002182{
2183 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2184 ioc->bus_type != SPI) ||
2185 (MptDriverClass[index] == MPTFC_DRIVER &&
2186 ioc->bus_type != FC) ||
2187 (MptDriverClass[index] == MPTSAS_DRIVER &&
2188 ioc->bus_type != SAS))
2189 /* make sure we only call the relevant reset handler
2190 * for the bus */
2191 return 0;
2192 return (MptResetHandlers[index])(ioc, reset_phase);
2193}
2194
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002196/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2198 * @ioc: Pointer to MPT adapter structure
2199 * @reason: Event word / reason
2200 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2201 *
2202 * This routine performs all the steps necessary to bring the IOC
2203 * to a OPERATIONAL state.
2204 *
2205 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2206 * MPT adapter.
2207 *
2208 * Returns:
2209 * 0 for success
2210 * -1 if failed to get board READY
2211 * -2 if READY but IOCFacts Failed
2212 * -3 if READY but PrimeIOCFifos Failed
2213 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302214 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302215 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 */
2217static int
2218mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2219{
2220 int hard_reset_done = 0;
2221 int alt_ioc_ready = 0;
2222 int hard;
2223 int rc=0;
2224 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 int ret = 0;
2226 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002227 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302228 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229
Eric Moore29dd3602007-09-14 18:46:51 -06002230 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2231 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232
2233 /* Disable reply interrupts (also blocks FreeQ) */
2234 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2235 ioc->active = 0;
2236
2237 if (ioc->alt_ioc) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302238 if (ioc->alt_ioc->active ||
2239 reason == MPT_HOSTEVENT_IOC_RECOVER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 reset_alt_ioc_active = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302241 /* Disable alt-IOC's reply interrupts
2242 * (and FreeQ) for a bit
2243 **/
2244 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2245 0xFFFFFFFF);
2246 ioc->alt_ioc->active = 0;
2247 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 }
2249
2250 hard = 1;
2251 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2252 hard = 0;
2253
2254 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2255 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002256 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2257 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258
2259 if (reset_alt_ioc_active && ioc->alt_ioc) {
2260 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002261 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2262 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002263 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 ioc->alt_ioc->active = 1;
2265 }
2266
2267 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302268 printk(MYIOC_s_WARN_FMT
2269 "NOT READY WARNING!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302271 ret = -1;
2272 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 }
2274
2275 /* hard_reset_done = 0 if a soft reset was performed
2276 * and 1 if a hard reset was performed.
2277 */
2278 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2279 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2280 alt_ioc_ready = 1;
2281 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05302282 printk(MYIOC_s_WARN_FMT
2283 ": alt-ioc Not ready WARNING!\n",
2284 ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 }
2286
2287 for (ii=0; ii<5; ii++) {
2288 /* Get IOC facts! Allow 5 retries */
2289 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2290 break;
2291 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002292
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293
2294 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002295 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2296 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 ret = -2;
2298 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2299 MptDisplayIocCapabilities(ioc);
2300 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002301
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 if (alt_ioc_ready) {
2303 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302304 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302305 "Initial Alt IocFacts failed rc=%x\n",
2306 ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 /* Retry - alt IOC was initialized once
2308 */
2309 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2310 }
2311 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302312 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002313 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 alt_ioc_ready = 0;
2315 reset_alt_ioc_active = 0;
2316 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2317 MptDisplayIocCapabilities(ioc->alt_ioc);
2318 }
2319 }
2320
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302321 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2322 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2323 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2324 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2325 IORESOURCE_IO);
2326 if (pci_enable_device(ioc->pcidev))
2327 return -5;
2328 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2329 "mpt"))
2330 return -5;
2331 }
2332
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002333 /*
2334 * Device is reset now. It must have de-asserted the interrupt line
2335 * (if it was asserted) and it should be safe to register for the
2336 * interrupt now.
2337 */
2338 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2339 ioc->pci_irq = -1;
2340 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302341 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002342 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002343 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302344 else
2345 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002346 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002347 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002348 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002349 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Kashyap, Desai2f187862009-05-29 16:52:37 +05302350 "interrupt %d!\n",
2351 ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302352 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002353 pci_disable_msi(ioc->pcidev);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302354 ret = -EBUSY;
2355 goto out;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002356 }
2357 irq_allocated = 1;
2358 ioc->pci_irq = ioc->pcidev->irq;
2359 pci_set_master(ioc->pcidev); /* ?? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302360 pci_set_drvdata(ioc->pcidev, ioc);
2361 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2362 "installed at interrupt %d\n", ioc->name,
2363 ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002364 }
2365 }
2366
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 /* Prime reply & request queues!
2368 * (mucho alloc's) Must be done prior to
2369 * init as upper addresses are needed for init.
2370 * If fails, continue with alt-ioc processing
2371 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302372 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
2373 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2375 ret = -3;
2376
2377 /* May need to check/upload firmware & data here!
2378 * If fails, continue with alt-ioc processing
2379 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302380 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
2381 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2383 ret = -4;
2384// NEW!
2385 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302386 printk(MYIOC_s_WARN_FMT
2387 ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002388 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 alt_ioc_ready = 0;
2390 reset_alt_ioc_active = 0;
2391 }
2392
2393 if (alt_ioc_ready) {
2394 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2395 alt_ioc_ready = 0;
2396 reset_alt_ioc_active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302397 printk(MYIOC_s_WARN_FMT
2398 ": alt-ioc: (%d) init failure WARNING!\n",
2399 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 }
2401 }
2402
2403 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2404 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302405 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002406 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407
2408 /* Controller is not operational, cannot do upload
2409 */
2410 if (ret == 0) {
2411 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002412 if (rc == 0) {
2413 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2414 /*
2415 * Maintain only one pointer to FW memory
2416 * so there will not be two attempt to
2417 * downloadboot onboard dual function
2418 * chips (mpt_adapter_disable,
2419 * mpt_diag_reset)
2420 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302421 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002422 "mpt_upload: alt_%s has cached_fw=%p \n",
2423 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302424 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002425 }
2426 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002427 printk(MYIOC_s_WARN_FMT
2428 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302429 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002430 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 }
2432 }
2433 }
2434
Kashyap, Desaifd761752009-05-29 16:39:06 +05302435 /* Enable MPT base driver management of EventNotification
2436 * and EventAck handling.
2437 */
2438 if ((ret == 0) && (!ioc->facts.EventState)) {
2439 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2440 "SendEventNotification\n",
2441 ioc->name));
2442 ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
2443 }
2444
2445 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2446 rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
2447
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 if (ret == 0) {
2449 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002450 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 ioc->active = 1;
2452 }
Kashyap, Desaifd761752009-05-29 16:39:06 +05302453 if (rc == 0) { /* alt ioc */
2454 if (reset_alt_ioc_active && ioc->alt_ioc) {
2455 /* (re)Enable alt-IOC! (reply interrupt) */
2456 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
2457 "reply irq re-enabled\n",
2458 ioc->alt_ioc->name));
2459 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2460 MPI_HIM_DIM);
2461 ioc->alt_ioc->active = 1;
2462 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 }
2464
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002466 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2468 * recursive scenario; GetLanConfigPages times out, timer expired
2469 * routine calls HardResetHandler, which calls into here again,
2470 * and we try GetLanConfigPages again...
2471 */
2472 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002473
2474 /*
2475 * Initalize link list for inactive raid volumes.
2476 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002477 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002478 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2479
Kashyap, Desai2f187862009-05-29 16:52:37 +05302480 switch (ioc->bus_type) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002481
Kashyap, Desai2f187862009-05-29 16:52:37 +05302482 case SAS:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002483 /* clear persistency table */
2484 if(ioc->facts.IOCExceptions &
2485 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2486 ret = mptbase_sas_persist_operation(ioc,
2487 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2488 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002489 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002490 }
2491
2492 /* Find IM volumes
2493 */
2494 mpt_findImVolumes(ioc);
2495
Kashyap, Desai2f187862009-05-29 16:52:37 +05302496 /* Check, and possibly reset, the coalescing value
2497 */
2498 mpt_read_ioc_pg_1(ioc);
2499
2500 break;
2501
2502 case FC:
2503 if ((ioc->pfacts[0].ProtocolFlags &
2504 MPI_PORTFACTS_PROTOCOL_LAN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2506 /*
2507 * Pre-fetch the ports LAN MAC address!
2508 * (LANPage1_t stuff)
2509 */
2510 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302511 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2512 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302513 "LanAddr = %02X:%02X:%02X"
2514 ":%02X:%02X:%02X\n",
2515 ioc->name, a[5], a[4],
2516 a[3], a[2], a[1], a[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302518 break;
2519
2520 case SPI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 /* Get NVRAM and adapter maximums from SPP 0 and 2
2522 */
2523 mpt_GetScsiPortSettings(ioc, 0);
2524
2525 /* Get version and length of SDP 1
2526 */
2527 mpt_readScsiDevicePageHeaders(ioc, 0);
2528
2529 /* Find IM volumes
2530 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002531 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 mpt_findImVolumes(ioc);
2533
2534 /* Check, and possibly reset, the coalescing value
2535 */
2536 mpt_read_ioc_pg_1(ioc);
2537
2538 mpt_read_ioc_pg_4(ioc);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302539
2540 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 }
2542
2543 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302544 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 }
2546
Eric Moore0ccdb002006-07-11 17:33:13 -06002547 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002548 if ((ret != 0) && irq_allocated) {
2549 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302550 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002551 pci_disable_msi(ioc->pcidev);
2552 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 return ret;
2554}
2555
2556/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002557/**
2558 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 * @ioc: Pointer to MPT adapter structure
2560 * @pdev: Pointer to (struct pci_dev) structure
2561 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002562 * Search for PCI bus/dev_function which matches
2563 * PCI bus/dev_function (+/-1) for newly discovered 929,
2564 * 929X, 1030 or 1035.
2565 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2567 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2568 */
2569static void
2570mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2571{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002572 struct pci_dev *peer=NULL;
2573 unsigned int slot = PCI_SLOT(pdev->devfn);
2574 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 MPT_ADAPTER *ioc_srch;
2576
Prakash, Sathya436ace72007-07-24 15:42:08 +05302577 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002578 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002579 ioc->name, pci_name(pdev), pdev->bus->number,
2580 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002581
2582 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2583 if (!peer) {
2584 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2585 if (!peer)
2586 return;
2587 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588
2589 list_for_each_entry(ioc_srch, &ioc_list, list) {
2590 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002591 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 /* Paranoia checks */
2593 if (ioc->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302594 printk(MYIOC_s_WARN_FMT
2595 "Oops, already bound (%s <==> %s)!\n",
2596 ioc->name, ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 break;
2598 } else if (ioc_srch->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302599 printk(MYIOC_s_WARN_FMT
2600 "Oops, already bound (%s <==> %s)!\n",
2601 ioc_srch->name, ioc_srch->name,
2602 ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 break;
2604 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302605 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2606 "FOUND! binding %s <==> %s\n",
2607 ioc->name, ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 ioc_srch->alt_ioc = ioc;
2609 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 }
2611 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002612 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613}
2614
2615/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002616/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002618 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 */
2620static void
2621mpt_adapter_disable(MPT_ADAPTER *ioc)
2622{
2623 int sz;
2624 int ret;
2625
2626 if (ioc->cached_fw != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302627 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2628 "%s: Pushing FW onto adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302629 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2630 ioc->cached_fw, CAN_SLEEP)) < 0) {
2631 printk(MYIOC_s_WARN_FMT
2632 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002633 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 }
2635 }
2636
Kashyap, Desai71278192009-05-29 16:53:14 +05302637 /*
2638 * Put the controller into ready state (if its not already)
2639 */
2640 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {
2641 if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
2642 CAN_SLEEP)) {
2643 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)
2644 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit "
2645 "reset failed to put ioc in ready state!\n",
2646 ioc->name, __func__);
2647 } else
2648 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset "
2649 "failed!\n", ioc->name, __func__);
2650 }
2651
2652
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 /* Disable adapter interrupts! */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302654 synchronize_irq(ioc->pcidev->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2656 ioc->active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302657
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 /* Clear any lingering interrupt */
2659 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302660 CHIPREG_READ32(&ioc->chip->IntStatus);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661
2662 if (ioc->alloc != NULL) {
2663 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002664 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2665 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 pci_free_consistent(ioc->pcidev, sz,
2667 ioc->alloc, ioc->alloc_dma);
2668 ioc->reply_frames = NULL;
2669 ioc->req_frames = NULL;
2670 ioc->alloc = NULL;
2671 ioc->alloc_total -= sz;
2672 }
2673
2674 if (ioc->sense_buf_pool != NULL) {
2675 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2676 pci_free_consistent(ioc->pcidev, sz,
2677 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2678 ioc->sense_buf_pool = NULL;
2679 ioc->alloc_total -= sz;
2680 }
2681
2682 if (ioc->events != NULL){
2683 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2684 kfree(ioc->events);
2685 ioc->events = NULL;
2686 ioc->alloc_total -= sz;
2687 }
2688
Prakash, Sathya984621b2008-01-11 14:42:17 +05302689 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002691 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002692 mpt_inactive_raid_list_free(ioc);
2693 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002694 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002695 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002696 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697
2698 if (ioc->spi_data.pIocPg4 != NULL) {
2699 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302700 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 ioc->spi_data.pIocPg4,
2702 ioc->spi_data.IocPg4_dma);
2703 ioc->spi_data.pIocPg4 = NULL;
2704 ioc->alloc_total -= sz;
2705 }
2706
2707 if (ioc->ReqToChain != NULL) {
2708 kfree(ioc->ReqToChain);
2709 kfree(ioc->RequestNB);
2710 ioc->ReqToChain = NULL;
2711 }
2712
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002713 kfree(ioc->ChainToChain);
2714 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002715
2716 if (ioc->HostPageBuffer != NULL) {
2717 if((ret = mpt_host_page_access_control(ioc,
2718 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002719 printk(MYIOC_s_ERR_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302720 ": %s: host page buffers free failed (%d)!\n",
2721 ioc->name, __func__, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002722 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302723 dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2724 "HostPageBuffer free @ %p, sz=%d bytes\n",
2725 ioc->name, ioc->HostPageBuffer,
2726 ioc->HostPageBuffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002727 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002728 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002729 ioc->HostPageBuffer = NULL;
2730 ioc->HostPageBuffer_sz = 0;
2731 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2732 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733
Kashyap, Desai2f187862009-05-29 16:52:37 +05302734 pci_set_drvdata(ioc->pcidev, NULL);
2735}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002737/**
2738 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 * @ioc: Pointer to MPT adapter structure
2740 *
2741 * This routine unregisters h/w resources and frees all alloc'd memory
2742 * associated with a MPT adapter structure.
2743 */
2744static void
2745mpt_adapter_dispose(MPT_ADAPTER *ioc)
2746{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002747 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002749 if (ioc == NULL)
2750 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002752 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002754 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002756 if (ioc->pci_irq != -1) {
2757 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302758 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002759 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002760 ioc->pci_irq = -1;
2761 }
2762
2763 if (ioc->memmap != NULL) {
2764 iounmap(ioc->memmap);
2765 ioc->memmap = NULL;
2766 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302768 pci_disable_device(ioc->pcidev);
2769 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2770
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002772 if (ioc->mtrr_reg > 0) {
2773 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002774 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002775 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776#endif
2777
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002778 /* Zap the adapter lookup ptr! */
2779 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002781 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002782 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2783 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002784
2785 if (ioc->alt_ioc)
2786 ioc->alt_ioc->alt_ioc = NULL;
2787
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002788 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789}
2790
2791/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002792/**
2793 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 * @ioc: Pointer to MPT adapter structure
2795 */
2796static void
2797MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2798{
2799 int i = 0;
2800
2801 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302802 if (ioc->prod_name)
2803 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 printk("Capabilities={");
2805
2806 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2807 printk("Initiator");
2808 i++;
2809 }
2810
2811 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2812 printk("%sTarget", i ? "," : "");
2813 i++;
2814 }
2815
2816 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2817 printk("%sLAN", i ? "," : "");
2818 i++;
2819 }
2820
2821#if 0
2822 /*
2823 * This would probably evoke more questions than it's worth
2824 */
2825 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2826 printk("%sLogBusAddr", i ? "," : "");
2827 i++;
2828 }
2829#endif
2830
2831 printk("}\n");
2832}
2833
2834/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002835/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2837 * @ioc: Pointer to MPT_ADAPTER structure
2838 * @force: Force hard KickStart of IOC
2839 * @sleepFlag: Specifies whether the process can sleep
2840 *
2841 * Returns:
2842 * 1 - DIAG reset and READY
2843 * 0 - READY initially OR soft reset and READY
2844 * -1 - Any failure on KickStart
2845 * -2 - Msg Unit Reset Failed
2846 * -3 - IO Unit Reset Failed
2847 * -4 - IOC owned by a PEER
2848 */
2849static int
2850MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2851{
2852 u32 ioc_state;
2853 int statefault = 0;
2854 int cntdn;
2855 int hard_reset_done = 0;
2856 int r;
2857 int ii;
2858 int whoinit;
2859
2860 /* Get current [raw] IOC state */
2861 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002862 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863
2864 /*
2865 * Check to see if IOC got left/stuck in doorbell handshake
2866 * grip of death. If so, hard reset the IOC.
2867 */
2868 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2869 statefault = 1;
2870 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2871 ioc->name);
2872 }
2873
2874 /* Is it already READY? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302875 if (!statefault &&
2876 ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) {
2877 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2878 "IOC is in READY state\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 return 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302880 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881
2882 /*
2883 * Check to see if IOC is in FAULT state.
2884 */
2885 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2886 statefault = 2;
2887 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002888 ioc->name);
2889 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2890 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 }
2892
2893 /*
2894 * Hmmm... Did it get left operational?
2895 */
2896 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302897 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 ioc->name));
2899
2900 /* Check WhoInit.
2901 * If PCI Peer, exit.
2902 * Else, if no fault conditions are present, issue a MessageUnitReset
2903 * Else, fall through to KickStart case
2904 */
2905 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002906 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2907 "whoinit 0x%x statefault %d force %d\n",
2908 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 if (whoinit == MPI_WHOINIT_PCI_PEER)
2910 return -4;
2911 else {
2912 if ((statefault == 0 ) && (force == 0)) {
2913 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2914 return 0;
2915 }
2916 statefault = 3;
2917 }
2918 }
2919
2920 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2921 if (hard_reset_done < 0)
2922 return -1;
2923
2924 /*
2925 * Loop here waiting for IOC to come READY.
2926 */
2927 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002928 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929
2930 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2931 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2932 /*
2933 * BIOS or previous driver load left IOC in OP state.
2934 * Reset messaging FIFOs.
2935 */
2936 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2937 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2938 return -2;
2939 }
2940 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2941 /*
2942 * Something is wrong. Try to get IOC back
2943 * to a known state.
2944 */
2945 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2946 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2947 return -3;
2948 }
2949 }
2950
2951 ii++; cntdn--;
2952 if (!cntdn) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302953 printk(MYIOC_s_ERR_FMT
2954 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
2955 ioc->name, ioc_state, (int)((ii+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 return -ETIME;
2957 }
2958
2959 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002960 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 } else {
2962 mdelay (1); /* 1 msec delay */
2963 }
2964
2965 }
2966
2967 if (statefault < 3) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302968 printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name,
2969 statefault == 1 ? "stuck handshake" : "IOC FAULT");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 }
2971
2972 return hard_reset_done;
2973}
2974
2975/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002976/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 * mpt_GetIocState - Get the current state of a MPT adapter.
2978 * @ioc: Pointer to MPT_ADAPTER structure
2979 * @cooked: Request raw or cooked IOC state
2980 *
2981 * Returns all IOC Doorbell register bits if cooked==0, else just the
2982 * Doorbell bits in MPI_IOC_STATE_MASK.
2983 */
2984u32
2985mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2986{
2987 u32 s, sc;
2988
2989 /* Get! */
2990 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 sc = s & MPI_IOC_STATE_MASK;
2992
2993 /* Save! */
2994 ioc->last_state = sc;
2995
2996 return cooked ? sc : s;
2997}
2998
2999/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003000/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 * GetIocFacts - Send IOCFacts request to MPT adapter.
3002 * @ioc: Pointer to MPT_ADAPTER structure
3003 * @sleepFlag: Specifies whether the process can sleep
3004 * @reason: If recovery, only update facts.
3005 *
3006 * Returns 0 for success, non-zero for failure.
3007 */
3008static int
3009GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
3010{
3011 IOCFacts_t get_facts;
3012 IOCFactsReply_t *facts;
3013 int r;
3014 int req_sz;
3015 int reply_sz;
3016 int sz;
3017 u32 status, vv;
3018 u8 shiftFactor=1;
3019
3020 /* IOC *must* NOT be in RESET state! */
3021 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303022 printk(KERN_ERR MYNAM
3023 ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
3024 ioc->name, ioc->last_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 return -44;
3026 }
3027
3028 facts = &ioc->facts;
3029
3030 /* Destination (reply area)... */
3031 reply_sz = sizeof(*facts);
3032 memset(facts, 0, reply_sz);
3033
3034 /* Request area (get_facts on the stack right now!) */
3035 req_sz = sizeof(get_facts);
3036 memset(&get_facts, 0, req_sz);
3037
3038 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
3039 /* Assert: All other get_facts fields are zero! */
3040
Prakash, Sathya436ace72007-07-24 15:42:08 +05303041 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003042 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 ioc->name, req_sz, reply_sz));
3044
3045 /* No non-zero fields in the get_facts request are greater than
3046 * 1 byte in size, so we can just fire it off as is.
3047 */
3048 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3049 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3050 if (r != 0)
3051 return r;
3052
3053 /*
3054 * Now byte swap (GRRR) the necessary fields before any further
3055 * inspection of reply contents.
3056 *
3057 * But need to do some sanity checks on MsgLength (byte) field
3058 * to make sure we don't zero IOC's req_sz!
3059 */
3060 /* Did we get a valid reply? */
3061 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3062 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3063 /*
3064 * If not been here, done that, save off first WhoInit value
3065 */
3066 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3067 ioc->FirstWhoInit = facts->WhoInit;
3068 }
3069
3070 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3071 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3072 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3073 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3074 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003075 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 /* CHECKME! IOCStatus, IOCLogInfo */
3077
3078 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3079 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3080
3081 /*
3082 * FC f/w version changed between 1.1 and 1.2
3083 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3084 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3085 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303086 if (facts->MsgVersion < MPI_VERSION_01_02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 /*
3088 * Handle old FC f/w style, convert to new...
3089 */
3090 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3091 facts->FWVersion.Word =
3092 ((oldv<<12) & 0xFF000000) |
3093 ((oldv<<8) & 0x000FFF00);
3094 } else
3095 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3096
3097 facts->ProductID = le16_to_cpu(facts->ProductID);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303098
Eric Mooreb506ade2007-01-29 09:45:37 -07003099 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3100 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3101 ioc->ir_firmware = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303102
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 facts->CurrentHostMfaHighAddr =
3104 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3105 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3106 facts->CurrentSenseBufferHighAddr =
3107 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3108 facts->CurReplyFrameSize =
3109 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003110 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111
3112 /*
3113 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3114 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3115 * to 14 in MPI-1.01.0x.
3116 */
3117 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
Kashyap, Desai2f187862009-05-29 16:52:37 +05303118 facts->MsgVersion > MPI_VERSION_01_00) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3120 }
3121
3122 sz = facts->FWImageSize;
3123 if ( sz & 0x01 )
3124 sz += 1;
3125 if ( sz & 0x02 )
3126 sz += 2;
3127 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003128
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 if (!facts->RequestFrameSize) {
3130 /* Something is wrong! */
3131 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3132 ioc->name);
3133 return -55;
3134 }
3135
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003136 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 vv = ((63 / (sz * 4)) + 1) & 0x03;
3138 ioc->NB_for_64_byte_frame = vv;
3139 while ( sz )
3140 {
3141 shiftFactor++;
3142 sz = sz >> 1;
3143 }
3144 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303145 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003146 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3147 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003148
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3150 /*
3151 * Set values for this IOC's request & reply frame sizes,
3152 * and request & reply queue depths...
3153 */
3154 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3155 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3156 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3157 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3158
Prakash, Sathya436ace72007-07-24 15:42:08 +05303159 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303161 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162 ioc->name, ioc->req_sz, ioc->req_depth));
3163
3164 /* Get port facts! */
3165 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3166 return r;
3167 }
3168 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003169 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3171 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3172 RequestFrameSize)/sizeof(u32)));
3173 return -66;
3174 }
3175
3176 return 0;
3177}
3178
3179/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003180/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 * GetPortFacts - Send PortFacts request to MPT adapter.
3182 * @ioc: Pointer to MPT_ADAPTER structure
3183 * @portnum: Port number
3184 * @sleepFlag: Specifies whether the process can sleep
3185 *
3186 * Returns 0 for success, non-zero for failure.
3187 */
3188static int
3189GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3190{
3191 PortFacts_t get_pfacts;
3192 PortFactsReply_t *pfacts;
3193 int ii;
3194 int req_sz;
3195 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003196 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197
3198 /* IOC *must* NOT be in RESET state! */
3199 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003200 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3201 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202 return -4;
3203 }
3204
3205 pfacts = &ioc->pfacts[portnum];
3206
3207 /* Destination (reply area)... */
3208 reply_sz = sizeof(*pfacts);
3209 memset(pfacts, 0, reply_sz);
3210
3211 /* Request area (get_pfacts on the stack right now!) */
3212 req_sz = sizeof(get_pfacts);
3213 memset(&get_pfacts, 0, req_sz);
3214
3215 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3216 get_pfacts.PortNumber = portnum;
3217 /* Assert: All other get_pfacts fields are zero! */
3218
Prakash, Sathya436ace72007-07-24 15:42:08 +05303219 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 ioc->name, portnum));
3221
3222 /* No non-zero fields in the get_pfacts request are greater than
3223 * 1 byte in size, so we can just fire it off as is.
3224 */
3225 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3226 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3227 if (ii != 0)
3228 return ii;
3229
3230 /* Did we get a valid reply? */
3231
3232 /* Now byte swap the necessary fields in the response. */
3233 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3234 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3235 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3236 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3237 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3238 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3239 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3240 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3241 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3242
Eric Moore793955f2007-01-29 09:42:20 -07003243 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3244 pfacts->MaxDevices;
3245 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3246 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3247
3248 /*
3249 * Place all the devices on channels
3250 *
3251 * (for debuging)
3252 */
3253 if (mpt_channel_mapping) {
3254 ioc->devices_per_bus = 1;
3255 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3256 }
3257
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 return 0;
3259}
3260
3261/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003262/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 * SendIocInit - Send IOCInit request to MPT adapter.
3264 * @ioc: Pointer to MPT_ADAPTER structure
3265 * @sleepFlag: Specifies whether the process can sleep
3266 *
3267 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3268 *
3269 * Returns 0 for success, non-zero for failure.
3270 */
3271static int
3272SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3273{
3274 IOCInit_t ioc_init;
3275 MPIDefaultReply_t init_reply;
3276 u32 state;
3277 int r;
3278 int count;
3279 int cntdn;
3280
3281 memset(&ioc_init, 0, sizeof(ioc_init));
3282 memset(&init_reply, 0, sizeof(init_reply));
3283
3284 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3285 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3286
3287 /* If we are in a recovery mode and we uploaded the FW image,
3288 * then this pointer is not NULL. Skip the upload a second time.
3289 * Set this flag if cached_fw set for either IOC.
3290 */
3291 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3292 ioc->upload_fw = 1;
3293 else
3294 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303295 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3297
Eric Moore793955f2007-01-29 09:42:20 -07003298 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3299 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303300
Prakash, Sathya436ace72007-07-24 15:42:08 +05303301 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003302 ioc->name, ioc->facts.MsgVersion));
3303 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3304 // set MsgVersion and HeaderVersion host driver was built with
3305 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3306 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003308 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3309 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3310 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3311 return -99;
3312 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3314
Kashyap, Desai2f187862009-05-29 16:52:37 +05303315 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 /* Save the upper 32-bits of the request
3317 * (reply) and sense buffers.
3318 */
3319 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3320 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3321 } else {
3322 /* Force 32-bit addressing */
3323 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3324 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3325 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003326
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3328 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003329 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3330 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331
Prakash, Sathya436ace72007-07-24 15:42:08 +05303332 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 ioc->name, &ioc_init));
3334
3335 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3336 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003337 if (r != 0) {
3338 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003340 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341
3342 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003343 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 */
3345
Prakash, Sathya436ace72007-07-24 15:42:08 +05303346 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003348
3349 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3350 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003352 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353
3354 /* YIKES! SUPER IMPORTANT!!!
3355 * Poll IocState until _OPERATIONAL while IOC is doing
3356 * LoopInit and TargetDiscovery!
3357 */
3358 count = 0;
3359 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3360 state = mpt_GetIocState(ioc, 1);
3361 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3362 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003363 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 } else {
3365 mdelay(1);
3366 }
3367
3368 if (!cntdn) {
3369 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3370 ioc->name, (int)((count+5)/HZ));
3371 return -9;
3372 }
3373
3374 state = mpt_GetIocState(ioc, 1);
3375 count++;
3376 }
Eric Moore29dd3602007-09-14 18:46:51 -06003377 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 ioc->name, count));
3379
Eric Mooreba856d32006-07-11 17:34:01 -06003380 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 return r;
3382}
3383
3384/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003385/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 * SendPortEnable - Send PortEnable request to MPT adapter port.
3387 * @ioc: Pointer to MPT_ADAPTER structure
3388 * @portnum: Port number to enable
3389 * @sleepFlag: Specifies whether the process can sleep
3390 *
3391 * Send PortEnable to bring IOC to OPERATIONAL state.
3392 *
3393 * Returns 0 for success, non-zero for failure.
3394 */
3395static int
3396SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3397{
3398 PortEnable_t port_enable;
3399 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003400 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 int req_sz;
3402 int reply_sz;
3403
3404 /* Destination... */
3405 reply_sz = sizeof(MPIDefaultReply_t);
3406 memset(&reply_buf, 0, reply_sz);
3407
3408 req_sz = sizeof(PortEnable_t);
3409 memset(&port_enable, 0, req_sz);
3410
3411 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3412 port_enable.PortNumber = portnum;
3413/* port_enable.ChainOffset = 0; */
3414/* port_enable.MsgFlags = 0; */
3415/* port_enable.MsgContext = 0; */
3416
Prakash, Sathya436ace72007-07-24 15:42:08 +05303417 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 ioc->name, portnum, &port_enable));
3419
3420 /* RAID FW may take a long time to enable
3421 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003422 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003423 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3424 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3425 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003426 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003427 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3428 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3429 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003431 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432}
3433
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003434/**
3435 * mpt_alloc_fw_memory - allocate firmware memory
3436 * @ioc: Pointer to MPT_ADAPTER structure
3437 * @size: total FW bytes
3438 *
3439 * If memory has already been allocated, the same (cached) value
3440 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303441 *
3442 * Return 0 if successfull, or non-zero for failure
3443 **/
3444int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3446{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303447 int rc;
3448
3449 if (ioc->cached_fw) {
3450 rc = 0; /* use already allocated memory */
3451 goto out;
3452 }
3453 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3455 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303456 rc = 0;
3457 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303459 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3460 if (!ioc->cached_fw) {
3461 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3462 ioc->name);
3463 rc = -1;
3464 } else {
3465 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3466 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3467 ioc->alloc_total += size;
3468 rc = 0;
3469 }
3470 out:
3471 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303473
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003474/**
3475 * mpt_free_fw_memory - free firmware memory
3476 * @ioc: Pointer to MPT_ADAPTER structure
3477 *
3478 * If alt_img is NULL, delete from ioc structure.
3479 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303480 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481void
3482mpt_free_fw_memory(MPT_ADAPTER *ioc)
3483{
3484 int sz;
3485
Prakash, Sathya984621b2008-01-11 14:42:17 +05303486 if (!ioc->cached_fw)
3487 return;
3488
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303490 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3491 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003492 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303493 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495}
3496
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003498/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3500 * @ioc: Pointer to MPT_ADAPTER structure
3501 * @sleepFlag: Specifies whether the process can sleep
3502 *
3503 * Returns 0 for success, >0 for handshake failure
3504 * <0 for fw upload failure.
3505 *
3506 * Remark: If bound IOC and a successful FWUpload was performed
3507 * on the bound IOC, the second image is discarded
3508 * and memory is free'd. Both channels must upload to prevent
3509 * IOC from running in degraded mode.
3510 */
3511static int
3512mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3513{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 u8 reply[sizeof(FWUploadReply_t)];
3515 FWUpload_t *prequest;
3516 FWUploadReply_t *preply;
3517 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 u32 flagsLength;
3519 int ii, sz, reply_sz;
3520 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303521 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 /* If the image size is 0, we are done.
3523 */
3524 if ((sz = ioc->facts.FWImageSize) == 0)
3525 return 0;
3526
Prakash, Sathya984621b2008-01-11 14:42:17 +05303527 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3528 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529
Eric Moore29dd3602007-09-14 18:46:51 -06003530 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3531 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003532
Eric Moorebc6e0892007-09-29 10:16:28 -06003533 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3534 kzalloc(ioc->req_sz, GFP_KERNEL);
3535 if (!prequest) {
3536 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3537 "while allocating memory \n", ioc->name));
3538 mpt_free_fw_memory(ioc);
3539 return -ENOMEM;
3540 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541
Eric Moorebc6e0892007-09-29 10:16:28 -06003542 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543
3544 reply_sz = sizeof(reply);
3545 memset(preply, 0, reply_sz);
3546
3547 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3548 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3549
3550 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3551 ptcsge->DetailsLength = 12;
3552 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3553 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003554 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303557 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3558 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3559 ioc->SGE_size;
3560 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3561 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3562 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003563 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303565 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3566 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567
Kashyap, Desai2f187862009-05-29 16:52:37 +05303568 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
3569 "rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570
3571 cmdStatus = -EFAULT;
3572 if (ii == 0) {
3573 /* Handshake transfer was complete and successful.
3574 * Check the Reply Frame.
3575 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303576 int status;
3577 status = le16_to_cpu(preply->IOCStatus) &
3578 MPI_IOCSTATUS_MASK;
3579 if (status == MPI_IOCSTATUS_SUCCESS &&
3580 ioc->facts.FWImageSize ==
3581 le32_to_cpu(preply->ActualImageSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 cmdStatus = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303584 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 ioc->name, cmdStatus));
3586
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003587
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 if (cmdStatus) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303589 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
3590 "freeing image \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 mpt_free_fw_memory(ioc);
3592 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003593 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594
3595 return cmdStatus;
3596}
3597
3598/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003599/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 * mpt_downloadboot - DownloadBoot code
3601 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003602 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 * @sleepFlag: Specifies whether the process can sleep
3604 *
3605 * FwDownloadBoot requires Programmed IO access.
3606 *
3607 * Returns 0 for success
3608 * -1 FW Image size is 0
3609 * -2 No valid cached_fw Pointer
3610 * <0 for fw upload failure.
3611 */
3612static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003613mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 MpiExtImageHeader_t *pExtImage;
3616 u32 fwSize;
3617 u32 diag0val;
3618 int count;
3619 u32 *ptrFw;
3620 u32 diagRwData;
3621 u32 nextImage;
3622 u32 load_addr;
3623 u32 ioc_state=0;
3624
Prakash, Sathya436ace72007-07-24 15:42:08 +05303625 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003626 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003627
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3629 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3630 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3631 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3632 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3633 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3634
3635 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3636
3637 /* wait 1 msec */
3638 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003639 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640 } else {
3641 mdelay (1);
3642 }
3643
3644 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3645 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3646
3647 for (count = 0; count < 30; count ++) {
3648 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3649 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303650 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 ioc->name, count));
3652 break;
3653 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003654 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003656 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003658 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 }
3660 }
3661
3662 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303663 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003664 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 ioc->name, diag0val));
3666 return -3;
3667 }
3668
3669 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3670 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3671 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3672 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3673 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3674 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3675
3676 /* Set the DiagRwEn and Disable ARM bits */
3677 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3678
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 fwSize = (pFwHeader->ImageSize + 3)/4;
3680 ptrFw = (u32 *) pFwHeader;
3681
3682 /* Write the LoadStartAddress to the DiagRw Address Register
3683 * using Programmed IO
3684 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003685 if (ioc->errata_flag_1064)
3686 pci_enable_io_access(ioc->pcidev);
3687
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303689 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690 ioc->name, pFwHeader->LoadStartAddress));
3691
Prakash, Sathya436ace72007-07-24 15:42:08 +05303692 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 ioc->name, fwSize*4, ptrFw));
3694 while (fwSize--) {
3695 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3696 }
3697
3698 nextImage = pFwHeader->NextImageHeaderOffset;
3699 while (nextImage) {
3700 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3701
3702 load_addr = pExtImage->LoadStartAddress;
3703
3704 fwSize = (pExtImage->ImageSize + 3) >> 2;
3705 ptrFw = (u32 *)pExtImage;
3706
Prakash, Sathya436ace72007-07-24 15:42:08 +05303707 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 +02003708 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3710
3711 while (fwSize--) {
3712 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3713 }
3714 nextImage = pExtImage->NextImageHeaderOffset;
3715 }
3716
3717 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303718 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3720
3721 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303722 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3724
3725 /* Clear the internal flash bad bit - autoincrementing register,
3726 * so must do two writes.
3727 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003728 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003729 /*
3730 * 1030 and 1035 H/W errata, workaround to access
3731 * the ClearFlashBadSignatureBit
3732 */
3733 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3734 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3735 diagRwData |= 0x40000000;
3736 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3737 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3738
3739 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3740 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3741 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3742 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3743
3744 /* wait 1 msec */
3745 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003746 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003747 } else {
3748 mdelay (1);
3749 }
3750 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003752 if (ioc->errata_flag_1064)
3753 pci_disable_io_access(ioc->pcidev);
3754
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303756 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003757 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003759 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303760 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761 ioc->name, diag0val));
3762 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3763
3764 /* Write 0xFF to reset the sequencer */
3765 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3766
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003767 if (ioc->bus_type == SAS) {
3768 ioc_state = mpt_GetIocState(ioc, 0);
3769 if ( (GetIocFacts(ioc, sleepFlag,
3770 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303771 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003772 ioc->name, ioc_state));
3773 return -EFAULT;
3774 }
3775 }
3776
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777 for (count=0; count<HZ*20; count++) {
3778 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303779 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3780 "downloadboot successful! (count=%d) IocState=%x\n",
3781 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003782 if (ioc->bus_type == SAS) {
3783 return 0;
3784 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303786 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3787 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788 ioc->name));
3789 return -EFAULT;
3790 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303791 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3792 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 ioc->name));
3794 return 0;
3795 }
3796 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003797 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798 } else {
3799 mdelay (10);
3800 }
3801 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303802 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3803 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804 return -EFAULT;
3805}
3806
3807/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003808/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809 * KickStart - Perform hard reset of MPT adapter.
3810 * @ioc: Pointer to MPT_ADAPTER structure
3811 * @force: Force hard reset
3812 * @sleepFlag: Specifies whether the process can sleep
3813 *
3814 * This routine places MPT adapter in diagnostic mode via the
3815 * WriteSequence register, and then performs a hard reset of adapter
3816 * via the Diagnostic register.
3817 *
3818 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3819 * or NO_SLEEP (interrupt thread, use mdelay)
3820 * force - 1 if doorbell active, board fault state
3821 * board operational, IOC_RECOVERY or
3822 * IOC_BRINGUP and there is an alt_ioc.
3823 * 0 else
3824 *
3825 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003826 * 1 - hard reset, READY
3827 * 0 - no reset due to History bit, READY
3828 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 * OR reset but failed to come READY
3830 * -2 - no reset, could not enter DIAG mode
3831 * -3 - reset but bad FW bit
3832 */
3833static int
3834KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3835{
3836 int hard_reset_done = 0;
3837 u32 ioc_state=0;
3838 int cnt,cntdn;
3839
Eric Moore29dd3602007-09-14 18:46:51 -06003840 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003841 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842 /* Always issue a Msg Unit Reset first. This will clear some
3843 * SCSI bus hang conditions.
3844 */
3845 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3846
3847 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003848 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 } else {
3850 mdelay (1000);
3851 }
3852 }
3853
3854 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3855 if (hard_reset_done < 0)
3856 return hard_reset_done;
3857
Prakash, Sathya436ace72007-07-24 15:42:08 +05303858 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003859 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003860
3861 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3862 for (cnt=0; cnt<cntdn; cnt++) {
3863 ioc_state = mpt_GetIocState(ioc, 1);
3864 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303865 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 ioc->name, cnt));
3867 return hard_reset_done;
3868 }
3869 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003870 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871 } else {
3872 mdelay (10);
3873 }
3874 }
3875
Eric Moore29dd3602007-09-14 18:46:51 -06003876 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3877 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 return -1;
3879}
3880
3881/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003882/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883 * mpt_diag_reset - Perform hard reset of the adapter.
3884 * @ioc: Pointer to MPT_ADAPTER structure
3885 * @ignore: Set if to honor and clear to ignore
3886 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003887 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 * else set to NO_SLEEP (use mdelay instead)
3889 *
3890 * This routine places the adapter in diagnostic mode via the
3891 * WriteSequence register and then performs a hard reset of adapter
3892 * via the Diagnostic register. Adapter should be in ready state
3893 * upon successful completion.
3894 *
3895 * Returns: 1 hard reset successful
3896 * 0 no reset performed because reset history bit set
3897 * -2 enabling diagnostic mode failed
3898 * -3 diagnostic reset failed
3899 */
3900static int
3901mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3902{
3903 u32 diag0val;
3904 u32 doorbell;
3905 int hard_reset_done = 0;
3906 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303908 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Kashyap, Desaid1306912009-08-05 12:53:51 +05303909 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910
Eric Moorecd2c6192007-01-29 09:47:47 -07003911 /* Clear any existing interrupts */
3912 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3913
Eric Moore87cf8982006-06-27 16:09:26 -06003914 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303915
3916 if (!ignore)
3917 return 0;
3918
Prakash, Sathya436ace72007-07-24 15:42:08 +05303919 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003920 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003921 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3922 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3923 if (sleepFlag == CAN_SLEEP)
3924 msleep(1);
3925 else
3926 mdelay(1);
3927
Kashyap, Desaid1306912009-08-05 12:53:51 +05303928 /*
3929 * Call each currently registered protocol IOC reset handler
3930 * with pre-reset indication.
3931 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3932 * MptResetHandlers[] registered yet.
3933 */
3934 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3935 if (MptResetHandlers[cb_idx])
3936 (*(MptResetHandlers[cb_idx]))(ioc,
3937 MPT_IOC_PRE_RESET);
3938 }
3939
Eric Moore87cf8982006-06-27 16:09:26 -06003940 for (count = 0; count < 60; count ++) {
3941 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3942 doorbell &= MPI_IOC_STATE_MASK;
3943
Prakash, Sathya436ace72007-07-24 15:42:08 +05303944 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003945 "looking for READY STATE: doorbell=%x"
3946 " count=%d\n",
3947 ioc->name, doorbell, count));
Kashyap, Desai2f187862009-05-29 16:52:37 +05303948
Eric Moore87cf8982006-06-27 16:09:26 -06003949 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003950 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003951 }
3952
3953 /* wait 1 sec */
3954 if (sleepFlag == CAN_SLEEP)
3955 msleep(1000);
3956 else
3957 mdelay(1000);
3958 }
3959 return -1;
3960 }
3961
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 /* Use "Diagnostic reset" method! (only thing available!) */
3963 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3964
Prakash, Sathya436ace72007-07-24 15:42:08 +05303965 if (ioc->debug_level & MPT_DEBUG) {
3966 if (ioc->alt_ioc)
3967 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3968 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303970 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971
3972 /* Do the reset if we are told to ignore the reset history
3973 * or if the reset history is 0
3974 */
3975 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3976 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3977 /* Write magic sequence to WriteSequence register
3978 * Loop until in diagnostic mode
3979 */
3980 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3981 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3982 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3983 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3984 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3985 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3986
3987 /* wait 100 msec */
3988 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003989 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 } else {
3991 mdelay (100);
3992 }
3993
3994 count++;
3995 if (count > 20) {
3996 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3997 ioc->name, diag0val);
3998 return -2;
3999
4000 }
4001
4002 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4003
Prakash, Sathya436ace72007-07-24 15:42:08 +05304004 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 ioc->name, diag0val));
4006 }
4007
Prakash, Sathya436ace72007-07-24 15:42:08 +05304008 if (ioc->debug_level & MPT_DEBUG) {
4009 if (ioc->alt_ioc)
4010 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4011 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304013 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 /*
4015 * Disable the ARM (Bug fix)
4016 *
4017 */
4018 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004019 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020
4021 /*
4022 * Now hit the reset bit in the Diagnostic register
4023 * (THE BIG HAMMER!) (Clears DRWE bit).
4024 */
4025 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
4026 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304027 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 ioc->name));
4029
4030 /*
4031 * Call each currently registered protocol IOC reset handler
4032 * with pre-reset indication.
4033 * NOTE: If we're doing _IOC_BRINGUP, there can be no
4034 * MptResetHandlers[] registered yet.
4035 */
Kashyap, Desaid1306912009-08-05 12:53:51 +05304036 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
4037 if (MptResetHandlers[cb_idx]) {
4038 mpt_signal_reset(cb_idx,
4039 ioc, MPT_IOC_PRE_RESET);
4040 if (ioc->alt_ioc) {
4041 mpt_signal_reset(cb_idx,
4042 ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 }
4044 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 }
4046
Eric Moore0ccdb002006-07-11 17:33:13 -06004047 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304048 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06004049 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304050 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4051 else
4052 cached_fw = NULL;
4053 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 /* If the DownloadBoot operation fails, the
4055 * IOC will be left unusable. This is a fatal error
4056 * case. _diag_reset will return < 0
4057 */
4058 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304059 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4061 break;
4062 }
4063
Prakash, Sathya436ace72007-07-24 15:42:08 +05304064 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304065 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 /* wait 1 sec */
4067 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004068 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 } else {
4070 mdelay (1000);
4071 }
4072 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304073 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004074 printk(MYIOC_s_WARN_FMT
4075 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076 }
4077
4078 } else {
4079 /* Wait for FW to reload and for board
4080 * to go to the READY state.
4081 * Maximum wait is 60 seconds.
4082 * If fail, no error will check again
4083 * with calling program.
4084 */
4085 for (count = 0; count < 60; count ++) {
4086 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4087 doorbell &= MPI_IOC_STATE_MASK;
4088
Kashyap, Desai2f187862009-05-29 16:52:37 +05304089 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4090 "looking for READY STATE: doorbell=%x"
4091 " count=%d\n", ioc->name, doorbell, count));
4092
Linus Torvalds1da177e2005-04-16 15:20:36 -07004093 if (doorbell == MPI_IOC_STATE_READY) {
4094 break;
4095 }
4096
4097 /* wait 1 sec */
4098 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004099 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100 } else {
4101 mdelay (1000);
4102 }
4103 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05304104
4105 if (doorbell != MPI_IOC_STATE_READY)
4106 printk(MYIOC_s_ERR_FMT "Failed to come READY "
4107 "after reset! IocState=%x", ioc->name,
4108 doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109 }
4110 }
4111
4112 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304113 if (ioc->debug_level & MPT_DEBUG) {
4114 if (ioc->alt_ioc)
4115 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4116 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4117 ioc->name, diag0val, diag1val));
4118 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004119
4120 /* Clear RESET_HISTORY bit! Place board in the
4121 * diagnostic mode to update the diag register.
4122 */
4123 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4124 count = 0;
4125 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4126 /* Write magic sequence to WriteSequence register
4127 * Loop until in diagnostic mode
4128 */
4129 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4130 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4131 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4132 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4133 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4134 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4135
4136 /* wait 100 msec */
4137 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004138 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139 } else {
4140 mdelay (100);
4141 }
4142
4143 count++;
4144 if (count > 20) {
4145 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4146 ioc->name, diag0val);
4147 break;
4148 }
4149 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4150 }
4151 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4152 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4153 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4154 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4155 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4156 ioc->name);
4157 }
4158
4159 /* Disable Diagnostic Mode
4160 */
4161 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4162
4163 /* Check FW reload status flags.
4164 */
4165 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4166 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4167 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4168 ioc->name, diag0val);
4169 return -3;
4170 }
4171
Prakash, Sathya436ace72007-07-24 15:42:08 +05304172 if (ioc->debug_level & MPT_DEBUG) {
4173 if (ioc->alt_ioc)
4174 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4175 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304177 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178
4179 /*
4180 * Reset flag that says we've enabled event notification
4181 */
4182 ioc->facts.EventState = 0;
4183
4184 if (ioc->alt_ioc)
4185 ioc->alt_ioc->facts.EventState = 0;
4186
4187 return hard_reset_done;
4188}
4189
4190/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004191/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 * SendIocReset - Send IOCReset request to MPT adapter.
4193 * @ioc: Pointer to MPT_ADAPTER structure
4194 * @reset_type: reset type, expected values are
4195 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004196 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197 *
4198 * Send IOCReset request to the MPT adapter.
4199 *
4200 * Returns 0 for success, non-zero for failure.
4201 */
4202static int
4203SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4204{
4205 int r;
4206 u32 state;
4207 int cntdn, count;
4208
Prakash, Sathya436ace72007-07-24 15:42:08 +05304209 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210 ioc->name, reset_type));
4211 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4212 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4213 return r;
4214
4215 /* FW ACK'd request, wait for READY state
4216 */
4217 count = 0;
4218 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4219
4220 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4221 cntdn--;
4222 count++;
4223 if (!cntdn) {
4224 if (sleepFlag != CAN_SLEEP)
4225 count *= 10;
4226
Kashyap, Desai2f187862009-05-29 16:52:37 +05304227 printk(MYIOC_s_ERR_FMT
4228 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
4229 ioc->name, state, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230 return -ETIME;
4231 }
4232
4233 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004234 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235 } else {
4236 mdelay (1); /* 1 msec delay */
4237 }
4238 }
4239
4240 /* TODO!
4241 * Cleanup all event stuff for this IOC; re-issue EventNotification
4242 * request if needed.
4243 */
4244 if (ioc->facts.Function)
4245 ioc->facts.EventState = 0;
4246
4247 return 0;
4248}
4249
4250/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004251/**
4252 * initChainBuffers - Allocate memory for and initialize chain buffers
4253 * @ioc: Pointer to MPT_ADAPTER structure
4254 *
4255 * Allocates memory for and initializes chain buffers,
4256 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004257 */
4258static int
4259initChainBuffers(MPT_ADAPTER *ioc)
4260{
4261 u8 *mem;
4262 int sz, ii, num_chain;
4263 int scale, num_sge, numSGE;
4264
4265 /* ReqToChain size must equal the req_depth
4266 * index = req_idx
4267 */
4268 if (ioc->ReqToChain == NULL) {
4269 sz = ioc->req_depth * sizeof(int);
4270 mem = kmalloc(sz, GFP_ATOMIC);
4271 if (mem == NULL)
4272 return -1;
4273
4274 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304275 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276 ioc->name, mem, sz));
4277 mem = kmalloc(sz, GFP_ATOMIC);
4278 if (mem == NULL)
4279 return -1;
4280
4281 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304282 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283 ioc->name, mem, sz));
4284 }
4285 for (ii = 0; ii < ioc->req_depth; ii++) {
4286 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4287 }
4288
4289 /* ChainToChain size must equal the total number
4290 * of chain buffers to be allocated.
4291 * index = chain_idx
4292 *
4293 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004294 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295 *
4296 * num_sge = num sge in request frame + last chain buffer
4297 * scale = num sge per chain buffer if no chain element
4298 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304299 scale = ioc->req_sz / ioc->SGE_size;
4300 if (ioc->sg_addr_size == sizeof(u64))
4301 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304303 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304305 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304307 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304309 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4310 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304312 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 ioc->name, num_sge, numSGE));
4314
Kashyap, Desai2f187862009-05-29 16:52:37 +05304315 if (ioc->bus_type == FC) {
4316 if (numSGE > MPT_SCSI_FC_SG_DEPTH)
4317 numSGE = MPT_SCSI_FC_SG_DEPTH;
4318 } else {
4319 if (numSGE > MPT_SCSI_SG_DEPTH)
4320 numSGE = MPT_SCSI_SG_DEPTH;
4321 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322
4323 num_chain = 1;
4324 while (numSGE - num_sge > 0) {
4325 num_chain++;
4326 num_sge += (scale - 1);
4327 }
4328 num_chain++;
4329
Prakash, Sathya436ace72007-07-24 15:42:08 +05304330 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331 ioc->name, numSGE, num_sge, num_chain));
4332
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004333 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334 num_chain *= MPT_SCSI_CAN_QUEUE;
Anatolij Gustschinf1053a72009-12-12 14:52:21 +01004335 else if (ioc->bus_type == SAS)
4336 num_chain *= MPT_SAS_CAN_QUEUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337 else
4338 num_chain *= MPT_FC_CAN_QUEUE;
4339
4340 ioc->num_chain = num_chain;
4341
4342 sz = num_chain * sizeof(int);
4343 if (ioc->ChainToChain == NULL) {
4344 mem = kmalloc(sz, GFP_ATOMIC);
4345 if (mem == NULL)
4346 return -1;
4347
4348 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304349 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350 ioc->name, mem, sz));
4351 } else {
4352 mem = (u8 *) ioc->ChainToChain;
4353 }
4354 memset(mem, 0xFF, sz);
4355 return num_chain;
4356}
4357
4358/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004359/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4361 * @ioc: Pointer to MPT_ADAPTER structure
4362 *
4363 * This routine allocates memory for the MPT reply and request frame
4364 * pools (if necessary), and primes the IOC reply FIFO with
4365 * reply frames.
4366 *
4367 * Returns 0 for success, non-zero for failure.
4368 */
4369static int
4370PrimeIocFifos(MPT_ADAPTER *ioc)
4371{
4372 MPT_FRAME_HDR *mf;
4373 unsigned long flags;
4374 dma_addr_t alloc_dma;
4375 u8 *mem;
4376 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304377 u64 dma_mask;
4378
4379 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380
4381 /* Prime reply FIFO... */
4382
4383 if (ioc->reply_frames == NULL) {
4384 if ( (num_chain = initChainBuffers(ioc)) < 0)
4385 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304386 /*
4387 * 1078 errata workaround for the 36GB limitation
4388 */
4389 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
Andrew Morton8e20ce92009-06-18 16:49:17 -07004390 ioc->dma_mask > DMA_BIT_MASK(35)) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304391 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4392 && !pci_set_consistent_dma_mask(ioc->pcidev,
4393 DMA_BIT_MASK(32))) {
Andrew Morton8e20ce92009-06-18 16:49:17 -07004394 dma_mask = DMA_BIT_MASK(35);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304395 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4396 "setting 35 bit addressing for "
4397 "Request/Reply/Chain and Sense Buffers\n",
4398 ioc->name));
4399 } else {
4400 /*Reseting DMA mask to 64 bit*/
4401 pci_set_dma_mask(ioc->pcidev,
4402 DMA_BIT_MASK(64));
4403 pci_set_consistent_dma_mask(ioc->pcidev,
4404 DMA_BIT_MASK(64));
4405
4406 printk(MYIOC_s_ERR_FMT
4407 "failed setting 35 bit addressing for "
4408 "Request/Reply/Chain and Sense Buffers\n",
4409 ioc->name);
4410 return -1;
4411 }
4412 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413
4414 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304415 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304417 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 ioc->name, reply_sz, reply_sz));
4419
4420 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304421 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304423 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 ioc->name, sz, sz));
4425 total_size += sz;
4426
4427 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304428 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304430 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431 ioc->name, sz, sz, num_chain));
4432
4433 total_size += sz;
4434 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4435 if (mem == NULL) {
4436 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4437 ioc->name);
4438 goto out_fail;
4439 }
4440
Prakash, Sathya436ace72007-07-24 15:42:08 +05304441 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4443
4444 memset(mem, 0, total_size);
4445 ioc->alloc_total += total_size;
4446 ioc->alloc = mem;
4447 ioc->alloc_dma = alloc_dma;
4448 ioc->alloc_sz = total_size;
4449 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4450 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4451
Prakash, Sathya436ace72007-07-24 15:42:08 +05304452 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004453 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4454
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 alloc_dma += reply_sz;
4456 mem += reply_sz;
4457
4458 /* Request FIFO - WE manage this! */
4459
4460 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4461 ioc->req_frames_dma = alloc_dma;
4462
Prakash, Sathya436ace72007-07-24 15:42:08 +05304463 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464 ioc->name, mem, (void *)(ulong)alloc_dma));
4465
4466 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4467
4468#if defined(CONFIG_MTRR) && 0
4469 /*
4470 * Enable Write Combining MTRR for IOC's memory region.
4471 * (at least as much as we can; "size and base must be
4472 * multiples of 4 kiB"
4473 */
4474 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4475 sz,
4476 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304477 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 ioc->name, ioc->req_frames_dma, sz));
4479#endif
4480
4481 for (i = 0; i < ioc->req_depth; i++) {
4482 alloc_dma += ioc->req_sz;
4483 mem += ioc->req_sz;
4484 }
4485
4486 ioc->ChainBuffer = mem;
4487 ioc->ChainBufferDMA = alloc_dma;
4488
Prakash, Sathya436ace72007-07-24 15:42:08 +05304489 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4491
4492 /* Initialize the free chain Q.
4493 */
4494
4495 INIT_LIST_HEAD(&ioc->FreeChainQ);
4496
4497 /* Post the chain buffers to the FreeChainQ.
4498 */
4499 mem = (u8 *)ioc->ChainBuffer;
4500 for (i=0; i < num_chain; i++) {
4501 mf = (MPT_FRAME_HDR *) mem;
4502 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4503 mem += ioc->req_sz;
4504 }
4505
4506 /* Initialize Request frames linked list
4507 */
4508 alloc_dma = ioc->req_frames_dma;
4509 mem = (u8 *) ioc->req_frames;
4510
4511 spin_lock_irqsave(&ioc->FreeQlock, flags);
4512 INIT_LIST_HEAD(&ioc->FreeQ);
4513 for (i = 0; i < ioc->req_depth; i++) {
4514 mf = (MPT_FRAME_HDR *) mem;
4515
4516 /* Queue REQUESTs *internally*! */
4517 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4518
4519 mem += ioc->req_sz;
4520 }
4521 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4522
4523 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4524 ioc->sense_buf_pool =
4525 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4526 if (ioc->sense_buf_pool == NULL) {
4527 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4528 ioc->name);
4529 goto out_fail;
4530 }
4531
4532 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4533 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304534 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4536
4537 }
4538
4539 /* Post Reply frames to FIFO
4540 */
4541 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304542 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4544
4545 for (i = 0; i < ioc->reply_depth; i++) {
4546 /* Write each address to the IOC! */
4547 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4548 alloc_dma += ioc->reply_sz;
4549 }
4550
Andrew Morton8e20ce92009-06-18 16:49:17 -07004551 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304552 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4553 ioc->dma_mask))
4554 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4555 "restoring 64 bit addressing\n", ioc->name));
4556
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557 return 0;
4558
4559out_fail:
Kashyap, Desai2f187862009-05-29 16:52:37 +05304560
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 if (ioc->alloc != NULL) {
4562 sz = ioc->alloc_sz;
4563 pci_free_consistent(ioc->pcidev,
4564 sz,
4565 ioc->alloc, ioc->alloc_dma);
4566 ioc->reply_frames = NULL;
4567 ioc->req_frames = NULL;
4568 ioc->alloc_total -= sz;
4569 }
4570 if (ioc->sense_buf_pool != NULL) {
4571 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4572 pci_free_consistent(ioc->pcidev,
4573 sz,
4574 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4575 ioc->sense_buf_pool = NULL;
4576 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304577
Andrew Morton8e20ce92009-06-18 16:49:17 -07004578 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304579 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4580 DMA_BIT_MASK(64)))
4581 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4582 "restoring 64 bit addressing\n", ioc->name));
4583
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 return -1;
4585}
4586
4587/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4588/**
4589 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4590 * from IOC via doorbell handshake method.
4591 * @ioc: Pointer to MPT_ADAPTER structure
4592 * @reqBytes: Size of the request in bytes
4593 * @req: Pointer to MPT request frame
4594 * @replyBytes: Expected size of the reply in bytes
4595 * @u16reply: Pointer to area where reply should be written
4596 * @maxwait: Max wait time for a reply (in seconds)
4597 * @sleepFlag: Specifies whether the process can sleep
4598 *
4599 * NOTES: It is the callers responsibility to byte-swap fields in the
4600 * request which are greater than 1 byte in size. It is also the
4601 * callers responsibility to byte-swap response fields which are
4602 * greater than 1 byte in size.
4603 *
4604 * Returns 0 for success, non-zero for failure.
4605 */
4606static int
4607mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004608 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609{
4610 MPIDefaultReply_t *mptReply;
4611 int failcnt = 0;
4612 int t;
4613
4614 /*
4615 * Get ready to cache a handshake reply
4616 */
4617 ioc->hs_reply_idx = 0;
4618 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4619 mptReply->MsgLength = 0;
4620
4621 /*
4622 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4623 * then tell IOC that we want to handshake a request of N words.
4624 * (WRITE u32val to Doorbell reg).
4625 */
4626 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4627 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4628 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4629 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4630
4631 /*
4632 * Wait for IOC's doorbell handshake int
4633 */
4634 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4635 failcnt++;
4636
Prakash, Sathya436ace72007-07-24 15:42:08 +05304637 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4639
4640 /* Read doorbell and check for active bit */
4641 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4642 return -1;
4643
4644 /*
4645 * Clear doorbell int (WRITE 0 to IntStatus reg),
4646 * then wait for IOC to ACKnowledge that it's ready for
4647 * our handshake request.
4648 */
4649 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4650 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4651 failcnt++;
4652
4653 if (!failcnt) {
4654 int ii;
4655 u8 *req_as_bytes = (u8 *) req;
4656
4657 /*
4658 * Stuff request words via doorbell handshake,
4659 * with ACK from IOC for each.
4660 */
4661 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4662 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4663 (req_as_bytes[(ii*4) + 1] << 8) |
4664 (req_as_bytes[(ii*4) + 2] << 16) |
4665 (req_as_bytes[(ii*4) + 3] << 24));
4666
4667 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4668 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4669 failcnt++;
4670 }
4671
Prakash, Sathya436ace72007-07-24 15:42:08 +05304672 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004673 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674
Prakash, Sathya436ace72007-07-24 15:42:08 +05304675 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004676 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4677
4678 /*
4679 * Wait for completion of doorbell handshake reply from the IOC
4680 */
4681 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4682 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004683
Prakash, Sathya436ace72007-07-24 15:42:08 +05304684 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4686
4687 /*
4688 * Copy out the cached reply...
4689 */
4690 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4691 u16reply[ii] = ioc->hs_reply[ii];
4692 } else {
4693 return -99;
4694 }
4695
4696 return -failcnt;
4697}
4698
4699/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004700/**
4701 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702 * @ioc: Pointer to MPT_ADAPTER structure
4703 * @howlong: How long to wait (in seconds)
4704 * @sleepFlag: Specifies whether the process can sleep
4705 *
4706 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004707 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4708 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709 *
4710 * Returns a negative value on failure, else wait loop count.
4711 */
4712static int
4713WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4714{
4715 int cntdn;
4716 int count = 0;
4717 u32 intstat=0;
4718
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004719 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720
4721 if (sleepFlag == CAN_SLEEP) {
4722 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004723 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4725 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4726 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727 count++;
4728 }
4729 } else {
4730 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004731 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4733 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4734 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735 count++;
4736 }
4737 }
4738
4739 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304740 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741 ioc->name, count));
4742 return count;
4743 }
4744
4745 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4746 ioc->name, count, intstat);
4747 return -1;
4748}
4749
4750/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004751/**
4752 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753 * @ioc: Pointer to MPT_ADAPTER structure
4754 * @howlong: How long to wait (in seconds)
4755 * @sleepFlag: Specifies whether the process can sleep
4756 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004757 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4758 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 *
4760 * Returns a negative value on failure, else wait loop count.
4761 */
4762static int
4763WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4764{
4765 int cntdn;
4766 int count = 0;
4767 u32 intstat=0;
4768
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004769 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770 if (sleepFlag == CAN_SLEEP) {
4771 while (--cntdn) {
4772 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4773 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4774 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004775 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 count++;
4777 }
4778 } else {
4779 while (--cntdn) {
4780 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4781 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4782 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004783 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784 count++;
4785 }
4786 }
4787
4788 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304789 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 ioc->name, count, howlong));
4791 return count;
4792 }
4793
4794 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4795 ioc->name, count, intstat);
4796 return -1;
4797}
4798
4799/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004800/**
4801 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 * @ioc: Pointer to MPT_ADAPTER structure
4803 * @howlong: How long to wait (in seconds)
4804 * @sleepFlag: Specifies whether the process can sleep
4805 *
4806 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4807 * Reply is cached to IOC private area large enough to hold a maximum
4808 * of 128 bytes of reply data.
4809 *
4810 * Returns a negative value on failure, else size of reply in WORDS.
4811 */
4812static int
4813WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4814{
4815 int u16cnt = 0;
4816 int failcnt = 0;
4817 int t;
4818 u16 *hs_reply = ioc->hs_reply;
4819 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4820 u16 hword;
4821
4822 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4823
4824 /*
4825 * Get first two u16's so we can look at IOC's intended reply MsgLength
4826 */
4827 u16cnt=0;
4828 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4829 failcnt++;
4830 } else {
4831 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4832 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4833 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4834 failcnt++;
4835 else {
4836 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4837 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4838 }
4839 }
4840
Prakash, Sathya436ace72007-07-24 15:42:08 +05304841 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004842 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4844
4845 /*
4846 * If no error (and IOC said MsgLength is > 0), piece together
4847 * reply 16 bits at a time.
4848 */
4849 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4850 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4851 failcnt++;
4852 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4853 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004854 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855 hs_reply[u16cnt] = hword;
4856 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4857 }
4858
4859 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4860 failcnt++;
4861 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4862
4863 if (failcnt) {
4864 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4865 ioc->name);
4866 return -failcnt;
4867 }
4868#if 0
4869 else if (u16cnt != (2 * mptReply->MsgLength)) {
4870 return -101;
4871 }
4872 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4873 return -102;
4874 }
4875#endif
4876
Prakash, Sathya436ace72007-07-24 15:42:08 +05304877 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004878 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879
Prakash, Sathya436ace72007-07-24 15:42:08 +05304880 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 ioc->name, t, u16cnt/2));
4882 return u16cnt/2;
4883}
4884
4885/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004886/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004887 * GetLanConfigPages - Fetch LANConfig pages.
4888 * @ioc: Pointer to MPT_ADAPTER structure
4889 *
4890 * Return: 0 for success
4891 * -ENOMEM if no memory available
4892 * -EPERM if not allowed due to ISR context
4893 * -EAGAIN if no msg frames currently available
4894 * -EFAULT for non-successful reply or no reply (timeout)
4895 */
4896static int
4897GetLanConfigPages(MPT_ADAPTER *ioc)
4898{
4899 ConfigPageHeader_t hdr;
4900 CONFIGPARMS cfg;
4901 LANPage0_t *ppage0_alloc;
4902 dma_addr_t page0_dma;
4903 LANPage1_t *ppage1_alloc;
4904 dma_addr_t page1_dma;
4905 int rc = 0;
4906 int data_sz;
4907 int copy_sz;
4908
4909 /* Get LAN Page 0 header */
4910 hdr.PageVersion = 0;
4911 hdr.PageLength = 0;
4912 hdr.PageNumber = 0;
4913 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004914 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915 cfg.physAddr = -1;
4916 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4917 cfg.dir = 0;
4918 cfg.pageAddr = 0;
4919 cfg.timeout = 0;
4920
4921 if ((rc = mpt_config(ioc, &cfg)) != 0)
4922 return rc;
4923
4924 if (hdr.PageLength > 0) {
4925 data_sz = hdr.PageLength * 4;
4926 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4927 rc = -ENOMEM;
4928 if (ppage0_alloc) {
4929 memset((u8 *)ppage0_alloc, 0, data_sz);
4930 cfg.physAddr = page0_dma;
4931 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4932
4933 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4934 /* save the data */
4935 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4936 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4937
4938 }
4939
4940 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4941
4942 /* FIXME!
4943 * Normalize endianness of structure data,
4944 * by byte-swapping all > 1 byte fields!
4945 */
4946
4947 }
4948
4949 if (rc)
4950 return rc;
4951 }
4952
4953 /* Get LAN Page 1 header */
4954 hdr.PageVersion = 0;
4955 hdr.PageLength = 0;
4956 hdr.PageNumber = 1;
4957 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004958 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004959 cfg.physAddr = -1;
4960 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4961 cfg.dir = 0;
4962 cfg.pageAddr = 0;
4963
4964 if ((rc = mpt_config(ioc, &cfg)) != 0)
4965 return rc;
4966
4967 if (hdr.PageLength == 0)
4968 return 0;
4969
4970 data_sz = hdr.PageLength * 4;
4971 rc = -ENOMEM;
4972 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4973 if (ppage1_alloc) {
4974 memset((u8 *)ppage1_alloc, 0, data_sz);
4975 cfg.physAddr = page1_dma;
4976 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4977
4978 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4979 /* save the data */
4980 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4981 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4982 }
4983
4984 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4985
4986 /* FIXME!
4987 * Normalize endianness of structure data,
4988 * by byte-swapping all > 1 byte fields!
4989 */
4990
4991 }
4992
4993 return rc;
4994}
4995
4996/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004997/**
4998 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004999 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005000 * @persist_opcode: see below
5001 *
5002 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
5003 * devices not currently present.
5004 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
5005 *
5006 * NOTE: Don't use not this function during interrupt time.
5007 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005008 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005009 */
5010
5011/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5012int
5013mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
5014{
5015 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
5016 SasIoUnitControlReply_t *sasIoUnitCntrReply;
5017 MPT_FRAME_HDR *mf = NULL;
5018 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305019 int ret = 0;
5020 unsigned long timeleft;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005021
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305022 mutex_lock(&ioc->mptbase_cmds.mutex);
5023
5024 /* init the internal cmd struct */
5025 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
5026 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005027
5028 /* insure garbage is not sent to fw */
5029 switch(persist_opcode) {
5030
5031 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
5032 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
5033 break;
5034
5035 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305036 ret = -1;
5037 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005038 }
5039
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305040 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
5041 __func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005042
5043 /* Get a MF for this command.
5044 */
5045 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305046 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
5047 ret = -1;
5048 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005049 }
5050
5051 mpi_hdr = (MPIHeader_t *) mf;
5052 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
5053 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
5054 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
5055 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
5056 sasIoUnitCntrReq->Operation = persist_opcode;
5057
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005058 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305059 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
5060 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
5061 ret = -ETIME;
5062 printk(KERN_DEBUG "%s: failed\n", __func__);
5063 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
5064 goto out;
5065 if (!timeleft) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09005066 printk(MYIOC_s_WARN_FMT
5067 "Issuing Reset from %s!!, doorbell=0x%08x\n",
5068 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05305069 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305070 mpt_free_msg_frame(ioc, mf);
5071 }
5072 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005073 }
5074
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305075 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
5076 ret = -1;
5077 goto out;
5078 }
5079
5080 sasIoUnitCntrReply =
5081 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5082 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5083 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5084 __func__, sasIoUnitCntrReply->IOCStatus,
5085 sasIoUnitCntrReply->IOCLogInfo);
5086 printk(KERN_DEBUG "%s: failed\n", __func__);
5087 ret = -1;
5088 } else
5089 printk(KERN_DEBUG "%s: success\n", __func__);
5090 out:
5091
5092 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5093 mutex_unlock(&ioc->mptbase_cmds.mutex);
5094 return ret;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005095}
5096
5097/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005098
5099static void
5100mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5101 MpiEventDataRaid_t * pRaidEventData)
5102{
5103 int volume;
5104 int reason;
5105 int disk;
5106 int status;
5107 int flags;
5108 int state;
5109
5110 volume = pRaidEventData->VolumeID;
5111 reason = pRaidEventData->ReasonCode;
5112 disk = pRaidEventData->PhysDiskNum;
5113 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5114 flags = (status >> 0) & 0xff;
5115 state = (status >> 8) & 0xff;
5116
5117 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5118 return;
5119 }
5120
5121 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5122 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5123 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005124 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5125 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005126 } else {
5127 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5128 ioc->name, volume);
5129 }
5130
5131 switch(reason) {
5132 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5133 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5134 ioc->name);
5135 break;
5136
5137 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5138
5139 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5140 ioc->name);
5141 break;
5142
5143 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5144 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5145 ioc->name);
5146 break;
5147
5148 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5149 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5150 ioc->name,
5151 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5152 ? "optimal"
5153 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5154 ? "degraded"
5155 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5156 ? "failed"
5157 : "state unknown",
5158 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5159 ? ", enabled" : "",
5160 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5161 ? ", quiesced" : "",
5162 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5163 ? ", resync in progress" : "" );
5164 break;
5165
5166 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5167 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5168 ioc->name, disk);
5169 break;
5170
5171 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5172 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5173 ioc->name);
5174 break;
5175
5176 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5177 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5178 ioc->name);
5179 break;
5180
5181 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5182 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5183 ioc->name);
5184 break;
5185
5186 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5187 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5188 ioc->name,
5189 state == MPI_PHYSDISK0_STATUS_ONLINE
5190 ? "online"
5191 : state == MPI_PHYSDISK0_STATUS_MISSING
5192 ? "missing"
5193 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5194 ? "not compatible"
5195 : state == MPI_PHYSDISK0_STATUS_FAILED
5196 ? "failed"
5197 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5198 ? "initializing"
5199 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5200 ? "offline requested"
5201 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5202 ? "failed requested"
5203 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5204 ? "offline"
5205 : "state unknown",
5206 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5207 ? ", out of sync" : "",
5208 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5209 ? ", quiesced" : "" );
5210 break;
5211
5212 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5213 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5214 ioc->name, disk);
5215 break;
5216
5217 case MPI_EVENT_RAID_RC_SMART_DATA:
5218 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5219 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5220 break;
5221
5222 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5223 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5224 ioc->name, disk);
5225 break;
5226 }
5227}
5228
5229/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005230/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5232 * @ioc: Pointer to MPT_ADAPTER structure
5233 *
5234 * Returns: 0 for success
5235 * -ENOMEM if no memory available
5236 * -EPERM if not allowed due to ISR context
5237 * -EAGAIN if no msg frames currently available
5238 * -EFAULT for non-successful reply or no reply (timeout)
5239 */
5240static int
5241GetIoUnitPage2(MPT_ADAPTER *ioc)
5242{
5243 ConfigPageHeader_t hdr;
5244 CONFIGPARMS cfg;
5245 IOUnitPage2_t *ppage_alloc;
5246 dma_addr_t page_dma;
5247 int data_sz;
5248 int rc;
5249
5250 /* Get the page header */
5251 hdr.PageVersion = 0;
5252 hdr.PageLength = 0;
5253 hdr.PageNumber = 2;
5254 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005255 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 cfg.physAddr = -1;
5257 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5258 cfg.dir = 0;
5259 cfg.pageAddr = 0;
5260 cfg.timeout = 0;
5261
5262 if ((rc = mpt_config(ioc, &cfg)) != 0)
5263 return rc;
5264
5265 if (hdr.PageLength == 0)
5266 return 0;
5267
5268 /* Read the config page */
5269 data_sz = hdr.PageLength * 4;
5270 rc = -ENOMEM;
5271 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5272 if (ppage_alloc) {
5273 memset((u8 *)ppage_alloc, 0, data_sz);
5274 cfg.physAddr = page_dma;
5275 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5276
5277 /* If Good, save data */
5278 if ((rc = mpt_config(ioc, &cfg)) == 0)
5279 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5280
5281 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5282 }
5283
5284 return rc;
5285}
5286
5287/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005288/**
5289 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290 * @ioc: Pointer to a Adapter Strucutre
5291 * @portnum: IOC port number
5292 *
5293 * Return: -EFAULT if read of config page header fails
5294 * or if no nvram
5295 * If read of SCSI Port Page 0 fails,
5296 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5297 * Adapter settings: async, narrow
5298 * Return 1
5299 * If read of SCSI Port Page 2 fails,
5300 * Adapter settings valid
5301 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5302 * Return 1
5303 * Else
5304 * Both valid
5305 * Return 0
5306 * CHECK - what type of locking mechanisms should be used????
5307 */
5308static int
5309mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5310{
5311 u8 *pbuf;
5312 dma_addr_t buf_dma;
5313 CONFIGPARMS cfg;
5314 ConfigPageHeader_t header;
5315 int ii;
5316 int data, rc = 0;
5317
5318 /* Allocate memory
5319 */
5320 if (!ioc->spi_data.nvram) {
5321 int sz;
5322 u8 *mem;
5323 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5324 mem = kmalloc(sz, GFP_ATOMIC);
5325 if (mem == NULL)
5326 return -EFAULT;
5327
5328 ioc->spi_data.nvram = (int *) mem;
5329
Prakash, Sathya436ace72007-07-24 15:42:08 +05305330 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331 ioc->name, ioc->spi_data.nvram, sz));
5332 }
5333
5334 /* Invalidate NVRAM information
5335 */
5336 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5337 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5338 }
5339
5340 /* Read SPP0 header, allocate memory, then read page.
5341 */
5342 header.PageVersion = 0;
5343 header.PageLength = 0;
5344 header.PageNumber = 0;
5345 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005346 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005347 cfg.physAddr = -1;
5348 cfg.pageAddr = portnum;
5349 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5350 cfg.dir = 0;
5351 cfg.timeout = 0; /* use default */
5352 if (mpt_config(ioc, &cfg) != 0)
5353 return -EFAULT;
5354
5355 if (header.PageLength > 0) {
5356 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5357 if (pbuf) {
5358 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5359 cfg.physAddr = buf_dma;
5360 if (mpt_config(ioc, &cfg) != 0) {
5361 ioc->spi_data.maxBusWidth = MPT_NARROW;
5362 ioc->spi_data.maxSyncOffset = 0;
5363 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5364 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5365 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305366 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5367 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005368 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369 } else {
5370 /* Save the Port Page 0 data
5371 */
5372 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5373 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5374 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5375
5376 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5377 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005378 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5379 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 ioc->name, pPP0->Capabilities));
5381 }
5382 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5383 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5384 if (data) {
5385 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5386 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5387 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305388 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5389 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005390 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 } else {
5392 ioc->spi_data.maxSyncOffset = 0;
5393 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5394 }
5395
5396 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5397
5398 /* Update the minSyncFactor based on bus type.
5399 */
5400 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5401 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5402
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005403 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305405 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5406 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005407 ioc->name, ioc->spi_data.minSyncFactor));
5408 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 }
5410 }
5411 if (pbuf) {
5412 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5413 }
5414 }
5415 }
5416
5417 /* SCSI Port Page 2 - Read the header then the page.
5418 */
5419 header.PageVersion = 0;
5420 header.PageLength = 0;
5421 header.PageNumber = 2;
5422 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005423 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424 cfg.physAddr = -1;
5425 cfg.pageAddr = portnum;
5426 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5427 cfg.dir = 0;
5428 if (mpt_config(ioc, &cfg) != 0)
5429 return -EFAULT;
5430
5431 if (header.PageLength > 0) {
5432 /* Allocate memory and read SCSI Port Page 2
5433 */
5434 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5435 if (pbuf) {
5436 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5437 cfg.physAddr = buf_dma;
5438 if (mpt_config(ioc, &cfg) != 0) {
5439 /* Nvram data is left with INVALID mark
5440 */
5441 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005442 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5443
5444 /* This is an ATTO adapter, read Page2 accordingly
5445 */
5446 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5447 ATTODeviceInfo_t *pdevice = NULL;
5448 u16 ATTOFlags;
5449
5450 /* Save the Port Page 2 data
5451 * (reformat into a 32bit quantity)
5452 */
5453 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5454 pdevice = &pPP2->DeviceSettings[ii];
5455 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5456 data = 0;
5457
5458 /* Translate ATTO device flags to LSI format
5459 */
5460 if (ATTOFlags & ATTOFLAG_DISC)
5461 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5462 if (ATTOFlags & ATTOFLAG_ID_ENB)
5463 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5464 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5465 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5466 if (ATTOFlags & ATTOFLAG_TAGGED)
5467 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5468 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5469 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5470
5471 data = (data << 16) | (pdevice->Period << 8) | 10;
5472 ioc->spi_data.nvram[ii] = data;
5473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474 } else {
5475 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5476 MpiDeviceInfo_t *pdevice = NULL;
5477
Moore, Ericd8e925d2006-01-16 18:53:06 -07005478 /*
5479 * Save "Set to Avoid SCSI Bus Resets" flag
5480 */
5481 ioc->spi_data.bus_reset =
5482 (le32_to_cpu(pPP2->PortFlags) &
5483 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5484 0 : 1 ;
5485
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486 /* Save the Port Page 2 data
5487 * (reformat into a 32bit quantity)
5488 */
5489 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5490 ioc->spi_data.PortFlags = data;
5491 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5492 pdevice = &pPP2->DeviceSettings[ii];
5493 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5494 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5495 ioc->spi_data.nvram[ii] = data;
5496 }
5497 }
5498
5499 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5500 }
5501 }
5502
5503 /* Update Adapter limits with those from NVRAM
5504 * Comment: Don't need to do this. Target performance
5505 * parameters will never exceed the adapters limits.
5506 */
5507
5508 return rc;
5509}
5510
5511/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005512/**
5513 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 * @ioc: Pointer to a Adapter Strucutre
5515 * @portnum: IOC port number
5516 *
5517 * Return: -EFAULT if read of config page header fails
5518 * or 0 if success.
5519 */
5520static int
5521mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5522{
5523 CONFIGPARMS cfg;
5524 ConfigPageHeader_t header;
5525
5526 /* Read the SCSI Device Page 1 header
5527 */
5528 header.PageVersion = 0;
5529 header.PageLength = 0;
5530 header.PageNumber = 1;
5531 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005532 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533 cfg.physAddr = -1;
5534 cfg.pageAddr = portnum;
5535 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5536 cfg.dir = 0;
5537 cfg.timeout = 0;
5538 if (mpt_config(ioc, &cfg) != 0)
5539 return -EFAULT;
5540
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005541 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5542 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543
5544 header.PageVersion = 0;
5545 header.PageLength = 0;
5546 header.PageNumber = 0;
5547 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5548 if (mpt_config(ioc, &cfg) != 0)
5549 return -EFAULT;
5550
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005551 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5552 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005553
Prakash, Sathya436ace72007-07-24 15:42:08 +05305554 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5556
Prakash, Sathya436ace72007-07-24 15:42:08 +05305557 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5559 return 0;
5560}
5561
Eric Mooreb506ade2007-01-29 09:45:37 -07005562/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005563 * mpt_inactive_raid_list_free - This clears this link list.
5564 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005565 **/
5566static void
5567mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5568{
5569 struct inactive_raid_component_info *component_info, *pNext;
5570
5571 if (list_empty(&ioc->raid_data.inactive_list))
5572 return;
5573
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005574 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005575 list_for_each_entry_safe(component_info, pNext,
5576 &ioc->raid_data.inactive_list, list) {
5577 list_del(&component_info->list);
5578 kfree(component_info);
5579 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005580 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005581}
5582
5583/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005584 * 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 -07005585 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005586 * @ioc : pointer to per adapter structure
5587 * @channel : volume channel
5588 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005589 **/
5590static void
5591mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5592{
5593 CONFIGPARMS cfg;
5594 ConfigPageHeader_t hdr;
5595 dma_addr_t dma_handle;
5596 pRaidVolumePage0_t buffer = NULL;
5597 int i;
5598 RaidPhysDiskPage0_t phys_disk;
5599 struct inactive_raid_component_info *component_info;
5600 int handle_inactive_volumes;
5601
5602 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5603 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5604 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5605 cfg.pageAddr = (channel << 8) + id;
5606 cfg.cfghdr.hdr = &hdr;
5607 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5608
5609 if (mpt_config(ioc, &cfg) != 0)
5610 goto out;
5611
5612 if (!hdr.PageLength)
5613 goto out;
5614
5615 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5616 &dma_handle);
5617
5618 if (!buffer)
5619 goto out;
5620
5621 cfg.physAddr = dma_handle;
5622 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5623
5624 if (mpt_config(ioc, &cfg) != 0)
5625 goto out;
5626
5627 if (!buffer->NumPhysDisks)
5628 goto out;
5629
5630 handle_inactive_volumes =
5631 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5632 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5633 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5634 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5635
5636 if (!handle_inactive_volumes)
5637 goto out;
5638
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005639 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005640 for (i = 0; i < buffer->NumPhysDisks; i++) {
5641 if(mpt_raid_phys_disk_pg0(ioc,
5642 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5643 continue;
5644
5645 if ((component_info = kmalloc(sizeof (*component_info),
5646 GFP_KERNEL)) == NULL)
5647 continue;
5648
5649 component_info->volumeID = id;
5650 component_info->volumeBus = channel;
5651 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5652 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5653 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5654 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5655
5656 list_add_tail(&component_info->list,
5657 &ioc->raid_data.inactive_list);
5658 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005659 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005660
5661 out:
5662 if (buffer)
5663 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5664 dma_handle);
5665}
5666
5667/**
5668 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5669 * @ioc: Pointer to a Adapter Structure
5670 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5671 * @phys_disk: requested payload data returned
5672 *
5673 * Return:
5674 * 0 on success
5675 * -EFAULT if read of config page header fails or data pointer not NULL
5676 * -ENOMEM if pci_alloc failed
5677 **/
5678int
Kashyap, Desai2f187862009-05-29 16:52:37 +05305679mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
5680 RaidPhysDiskPage0_t *phys_disk)
Eric Mooreb506ade2007-01-29 09:45:37 -07005681{
Kashyap, Desai2f187862009-05-29 16:52:37 +05305682 CONFIGPARMS cfg;
5683 ConfigPageHeader_t hdr;
Eric Mooreb506ade2007-01-29 09:45:37 -07005684 dma_addr_t dma_handle;
5685 pRaidPhysDiskPage0_t buffer = NULL;
5686 int rc;
5687
5688 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5689 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
Kashyap, Desai2f187862009-05-29 16:52:37 +05305690 memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
Eric Mooreb506ade2007-01-29 09:45:37 -07005691
Kashyap, Desai2f187862009-05-29 16:52:37 +05305692 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
Eric Mooreb506ade2007-01-29 09:45:37 -07005693 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5694 cfg.cfghdr.hdr = &hdr;
5695 cfg.physAddr = -1;
5696 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5697
5698 if (mpt_config(ioc, &cfg) != 0) {
5699 rc = -EFAULT;
5700 goto out;
5701 }
5702
5703 if (!hdr.PageLength) {
5704 rc = -EFAULT;
5705 goto out;
5706 }
5707
5708 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5709 &dma_handle);
5710
5711 if (!buffer) {
5712 rc = -ENOMEM;
5713 goto out;
5714 }
5715
5716 cfg.physAddr = dma_handle;
5717 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5718 cfg.pageAddr = phys_disk_num;
5719
5720 if (mpt_config(ioc, &cfg) != 0) {
5721 rc = -EFAULT;
5722 goto out;
5723 }
5724
5725 rc = 0;
5726 memcpy(phys_disk, buffer, sizeof(*buffer));
5727 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5728
5729 out:
5730
5731 if (buffer)
5732 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5733 dma_handle);
5734
5735 return rc;
5736}
5737
Linus Torvalds1da177e2005-04-16 15:20:36 -07005738/**
Kashyap, Desaia7938b02009-05-29 16:53:56 +05305739 * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
5740 * @ioc: Pointer to a Adapter Structure
5741 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5742 *
5743 * Return:
5744 * returns number paths
5745 **/
5746int
5747mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
5748{
5749 CONFIGPARMS cfg;
5750 ConfigPageHeader_t hdr;
5751 dma_addr_t dma_handle;
5752 pRaidPhysDiskPage1_t buffer = NULL;
5753 int rc;
5754
5755 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5756 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5757
5758 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5759 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5760 hdr.PageNumber = 1;
5761 cfg.cfghdr.hdr = &hdr;
5762 cfg.physAddr = -1;
5763 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5764
5765 if (mpt_config(ioc, &cfg) != 0) {
5766 rc = 0;
5767 goto out;
5768 }
5769
5770 if (!hdr.PageLength) {
5771 rc = 0;
5772 goto out;
5773 }
5774
5775 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5776 &dma_handle);
5777
5778 if (!buffer) {
5779 rc = 0;
5780 goto out;
5781 }
5782
5783 cfg.physAddr = dma_handle;
5784 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5785 cfg.pageAddr = phys_disk_num;
5786
5787 if (mpt_config(ioc, &cfg) != 0) {
5788 rc = 0;
5789 goto out;
5790 }
5791
5792 rc = buffer->NumPhysDiskPaths;
5793 out:
5794
5795 if (buffer)
5796 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5797 dma_handle);
5798
5799 return rc;
5800}
5801EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
5802
5803/**
5804 * mpt_raid_phys_disk_pg1 - returns phys disk page 1
5805 * @ioc: Pointer to a Adapter Structure
5806 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5807 * @phys_disk: requested payload data returned
5808 *
5809 * Return:
5810 * 0 on success
5811 * -EFAULT if read of config page header fails or data pointer not NULL
5812 * -ENOMEM if pci_alloc failed
5813 **/
5814int
5815mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
5816 RaidPhysDiskPage1_t *phys_disk)
5817{
5818 CONFIGPARMS cfg;
5819 ConfigPageHeader_t hdr;
5820 dma_addr_t dma_handle;
5821 pRaidPhysDiskPage1_t buffer = NULL;
5822 int rc;
5823 int i;
5824 __le64 sas_address;
5825
5826 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5827 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5828 rc = 0;
5829
5830 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5831 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5832 hdr.PageNumber = 1;
5833 cfg.cfghdr.hdr = &hdr;
5834 cfg.physAddr = -1;
5835 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5836
5837 if (mpt_config(ioc, &cfg) != 0) {
5838 rc = -EFAULT;
5839 goto out;
5840 }
5841
5842 if (!hdr.PageLength) {
5843 rc = -EFAULT;
5844 goto out;
5845 }
5846
5847 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5848 &dma_handle);
5849
5850 if (!buffer) {
5851 rc = -ENOMEM;
5852 goto out;
5853 }
5854
5855 cfg.physAddr = dma_handle;
5856 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5857 cfg.pageAddr = phys_disk_num;
5858
5859 if (mpt_config(ioc, &cfg) != 0) {
5860 rc = -EFAULT;
5861 goto out;
5862 }
5863
5864 phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
5865 phys_disk->PhysDiskNum = phys_disk_num;
5866 for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
5867 phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
5868 phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
5869 phys_disk->Path[i].OwnerIdentifier =
5870 buffer->Path[i].OwnerIdentifier;
5871 phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
5872 memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
5873 sas_address = le64_to_cpu(sas_address);
5874 memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
5875 memcpy(&sas_address,
5876 &buffer->Path[i].OwnerWWID, sizeof(__le64));
5877 sas_address = le64_to_cpu(sas_address);
5878 memcpy(&phys_disk->Path[i].OwnerWWID,
5879 &sas_address, sizeof(__le64));
5880 }
5881
5882 out:
5883
5884 if (buffer)
5885 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5886 dma_handle);
5887
5888 return rc;
5889}
5890EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
5891
5892
5893/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005894 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5895 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005896 *
5897 * Return:
5898 * 0 on success
5899 * -EFAULT if read of config page header fails or data pointer not NULL
5900 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005901 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902int
5903mpt_findImVolumes(MPT_ADAPTER *ioc)
5904{
5905 IOCPage2_t *pIoc2;
5906 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005907 dma_addr_t ioc2_dma;
5908 CONFIGPARMS cfg;
5909 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910 int rc = 0;
5911 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005912 int i;
5913
5914 if (!ioc->ir_firmware)
5915 return 0;
5916
5917 /* Free the old page
5918 */
5919 kfree(ioc->raid_data.pIocPg2);
5920 ioc->raid_data.pIocPg2 = NULL;
5921 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005922
5923 /* Read IOCP2 header then the page.
5924 */
5925 header.PageVersion = 0;
5926 header.PageLength = 0;
5927 header.PageNumber = 2;
5928 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005929 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005930 cfg.physAddr = -1;
5931 cfg.pageAddr = 0;
5932 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5933 cfg.dir = 0;
5934 cfg.timeout = 0;
5935 if (mpt_config(ioc, &cfg) != 0)
5936 return -EFAULT;
5937
5938 if (header.PageLength == 0)
5939 return -EFAULT;
5940
5941 iocpage2sz = header.PageLength * 4;
5942 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5943 if (!pIoc2)
5944 return -ENOMEM;
5945
5946 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5947 cfg.physAddr = ioc2_dma;
5948 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005949 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005950
Eric Mooreb506ade2007-01-29 09:45:37 -07005951 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5952 if (!mem)
5953 goto out;
5954
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005956 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957
Eric Mooreb506ade2007-01-29 09:45:37 -07005958 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959
Eric Mooreb506ade2007-01-29 09:45:37 -07005960 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5961 mpt_inactive_raid_volumes(ioc,
5962 pIoc2->RaidVolume[i].VolumeBus,
5963 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005964
Eric Mooreb506ade2007-01-29 09:45:37 -07005965 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005966 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5967
5968 return rc;
5969}
5970
Moore, Ericc972c702006-03-14 09:14:06 -07005971static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005972mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5973{
5974 IOCPage3_t *pIoc3;
5975 u8 *mem;
5976 CONFIGPARMS cfg;
5977 ConfigPageHeader_t header;
5978 dma_addr_t ioc3_dma;
5979 int iocpage3sz = 0;
5980
5981 /* Free the old page
5982 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005983 kfree(ioc->raid_data.pIocPg3);
5984 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005985
5986 /* There is at least one physical disk.
5987 * Read and save IOC Page 3
5988 */
5989 header.PageVersion = 0;
5990 header.PageLength = 0;
5991 header.PageNumber = 3;
5992 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005993 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994 cfg.physAddr = -1;
5995 cfg.pageAddr = 0;
5996 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5997 cfg.dir = 0;
5998 cfg.timeout = 0;
5999 if (mpt_config(ioc, &cfg) != 0)
6000 return 0;
6001
6002 if (header.PageLength == 0)
6003 return 0;
6004
6005 /* Read Header good, alloc memory
6006 */
6007 iocpage3sz = header.PageLength * 4;
6008 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
6009 if (!pIoc3)
6010 return 0;
6011
6012 /* Read the Page and save the data
6013 * into malloc'd memory.
6014 */
6015 cfg.physAddr = ioc3_dma;
6016 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6017 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07006018 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006019 if (mem) {
6020 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006021 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006022 }
6023 }
6024
6025 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
6026
6027 return 0;
6028}
6029
6030static void
6031mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
6032{
6033 IOCPage4_t *pIoc4;
6034 CONFIGPARMS cfg;
6035 ConfigPageHeader_t header;
6036 dma_addr_t ioc4_dma;
6037 int iocpage4sz;
6038
6039 /* Read and save IOC Page 4
6040 */
6041 header.PageVersion = 0;
6042 header.PageLength = 0;
6043 header.PageNumber = 4;
6044 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006045 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006046 cfg.physAddr = -1;
6047 cfg.pageAddr = 0;
6048 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6049 cfg.dir = 0;
6050 cfg.timeout = 0;
6051 if (mpt_config(ioc, &cfg) != 0)
6052 return;
6053
6054 if (header.PageLength == 0)
6055 return;
6056
6057 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
6058 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
6059 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
6060 if (!pIoc4)
6061 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06006062 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006063 } else {
6064 ioc4_dma = ioc->spi_data.IocPg4_dma;
6065 iocpage4sz = ioc->spi_data.IocPg4Sz;
6066 }
6067
6068 /* Read the Page into dma memory.
6069 */
6070 cfg.physAddr = ioc4_dma;
6071 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6072 if (mpt_config(ioc, &cfg) == 0) {
6073 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
6074 ioc->spi_data.IocPg4_dma = ioc4_dma;
6075 ioc->spi_data.IocPg4Sz = iocpage4sz;
6076 } else {
6077 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
6078 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06006079 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006080 }
6081}
6082
6083static void
6084mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
6085{
6086 IOCPage1_t *pIoc1;
6087 CONFIGPARMS cfg;
6088 ConfigPageHeader_t header;
6089 dma_addr_t ioc1_dma;
6090 int iocpage1sz = 0;
6091 u32 tmp;
6092
6093 /* Check the Coalescing Timeout in IOC Page 1
6094 */
6095 header.PageVersion = 0;
6096 header.PageLength = 0;
6097 header.PageNumber = 1;
6098 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006099 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006100 cfg.physAddr = -1;
6101 cfg.pageAddr = 0;
6102 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6103 cfg.dir = 0;
6104 cfg.timeout = 0;
6105 if (mpt_config(ioc, &cfg) != 0)
6106 return;
6107
6108 if (header.PageLength == 0)
6109 return;
6110
6111 /* Read Header good, alloc memory
6112 */
6113 iocpage1sz = header.PageLength * 4;
6114 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
6115 if (!pIoc1)
6116 return;
6117
6118 /* Read the Page and check coalescing timeout
6119 */
6120 cfg.physAddr = ioc1_dma;
6121 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6122 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306123
Linus Torvalds1da177e2005-04-16 15:20:36 -07006124 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
6125 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
6126 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
6127
Prakash, Sathya436ace72007-07-24 15:42:08 +05306128 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006129 ioc->name, tmp));
6130
6131 if (tmp > MPT_COALESCING_TIMEOUT) {
6132 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
6133
6134 /* Write NVRAM and current
6135 */
6136 cfg.dir = 1;
6137 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
6138 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306139 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006140 ioc->name, MPT_COALESCING_TIMEOUT));
6141
6142 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
6143 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306144 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6145 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006146 ioc->name, MPT_COALESCING_TIMEOUT));
6147 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306148 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6149 "Reset NVRAM Coalescing Timeout Failed\n",
6150 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006151 }
6152
6153 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306154 dprintk(ioc, printk(MYIOC_s_WARN_FMT
6155 "Reset of Current Coalescing Timeout Failed!\n",
6156 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006157 }
6158 }
6159
6160 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306161 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006162 }
6163 }
6164
6165 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
6166
6167 return;
6168}
6169
Prakash, Sathyaedb90682007-07-17 14:39:14 +05306170static void
6171mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
6172{
6173 CONFIGPARMS cfg;
6174 ConfigPageHeader_t hdr;
6175 dma_addr_t buf_dma;
6176 ManufacturingPage0_t *pbuf = NULL;
6177
6178 memset(&cfg, 0 , sizeof(CONFIGPARMS));
6179 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
6180
6181 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
6182 cfg.cfghdr.hdr = &hdr;
6183 cfg.physAddr = -1;
6184 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6185 cfg.timeout = 10;
6186
6187 if (mpt_config(ioc, &cfg) != 0)
6188 goto out;
6189
6190 if (!cfg.cfghdr.hdr->PageLength)
6191 goto out;
6192
6193 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6194 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
6195 if (!pbuf)
6196 goto out;
6197
6198 cfg.physAddr = buf_dma;
6199
6200 if (mpt_config(ioc, &cfg) != 0)
6201 goto out;
6202
6203 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
6204 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
6205 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
6206
6207 out:
6208
6209 if (pbuf)
6210 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
6211}
6212
Linus Torvalds1da177e2005-04-16 15:20:36 -07006213/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006214/**
6215 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006216 * @ioc: Pointer to MPT_ADAPTER structure
6217 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05306218 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219 */
6220static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05306221SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006222{
Kashyap, Desaifd761752009-05-29 16:39:06 +05306223 EventNotification_t evn;
6224 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006225
Kashyap, Desaifd761752009-05-29 16:39:06 +05306226 memset(&evn, 0, sizeof(EventNotification_t));
6227 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228
Kashyap, Desaifd761752009-05-29 16:39:06 +05306229 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
6230 evn.Switch = EvSwitch;
6231 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006232
Kashyap, Desaifd761752009-05-29 16:39:06 +05306233 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6234 "Sending EventNotification (%d) request %p\n",
6235 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006236
Kashyap, Desaifd761752009-05-29 16:39:06 +05306237 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6238 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6239 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006240}
6241
6242/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6243/**
6244 * SendEventAck - Send EventAck request to MPT adapter.
6245 * @ioc: Pointer to MPT_ADAPTER structure
6246 * @evnp: Pointer to original EventNotification request
6247 */
6248static int
6249SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6250{
6251 EventAck_t *pAck;
6252
6253 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306254 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306255 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006256 return -1;
6257 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006258
Prakash, Sathya436ace72007-07-24 15:42:08 +05306259 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006260
6261 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6262 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006263 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006265 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006266 pAck->Event = evnp->Event;
6267 pAck->EventContext = evnp->EventContext;
6268
6269 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6270
6271 return 0;
6272}
6273
6274/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6275/**
6276 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006277 * @ioc: Pointer to an adapter structure
6278 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006279 * action, page address, direction, physical address
6280 * and pointer to a configuration page header
6281 * Page header is updated.
6282 *
6283 * Returns 0 for success
6284 * -EPERM if not allowed due to ISR context
6285 * -EAGAIN if no msg frames currently available
6286 * -EFAULT for non-successful reply or no reply (timeout)
6287 */
6288int
6289mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6290{
6291 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306292 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006293 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006294 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306295 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006296 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306297 long timeout;
6298 int ret;
6299 u8 page_type = 0, extend_page;
6300 unsigned long timeleft;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306301 unsigned long flags;
6302 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306303 u8 issue_hard_reset = 0;
6304 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006305
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006306 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006307 * to be in ISR context, because that is fatal!
6308 */
6309 in_isr = in_interrupt();
6310 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306311 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006312 ioc->name));
6313 return -EPERM;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306314 }
6315
6316 /* don't send a config page during diag reset */
6317 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6318 if (ioc->ioc_reset_in_progress) {
6319 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6320 "%s: busy with host reset\n", ioc->name, __func__));
6321 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6322 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006323 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306324 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006325
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306326 /* don't send if no chance of success */
6327 if (!ioc->active ||
6328 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6329 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6330 "%s: ioc not operational, %d, %xh\n",
6331 ioc->name, __func__, ioc->active,
6332 mpt_GetIocState(ioc, 0)));
6333 return -EFAULT;
6334 }
6335
6336 retry_config:
6337 mutex_lock(&ioc->mptbase_cmds.mutex);
6338 /* init the internal cmd struct */
6339 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6340 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6341
Linus Torvalds1da177e2005-04-16 15:20:36 -07006342 /* Get and Populate a free Frame
6343 */
6344 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306345 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6346 "mpt_config: no msg frames!\n", ioc->name));
6347 ret = -EAGAIN;
6348 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006349 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306350
Linus Torvalds1da177e2005-04-16 15:20:36 -07006351 pReq = (Config_t *)mf;
6352 pReq->Action = pCfg->action;
6353 pReq->Reserved = 0;
6354 pReq->ChainOffset = 0;
6355 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006356
6357 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006358 pReq->ExtPageLength = 0;
6359 pReq->ExtPageType = 0;
6360 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006361
Linus Torvalds1da177e2005-04-16 15:20:36 -07006362 for (ii=0; ii < 8; ii++)
6363 pReq->Reserved2[ii] = 0;
6364
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006365 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6366 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6367 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6368 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6369
6370 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6371 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6372 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6373 pReq->ExtPageType = pExtHdr->ExtPageType;
6374 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6375
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306376 /* Page Length must be treated as a reserved field for the
6377 * extended header.
6378 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006379 pReq->Header.PageLength = 0;
6380 }
6381
Linus Torvalds1da177e2005-04-16 15:20:36 -07006382 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6383
6384 /* Add a SGE to the config request.
6385 */
6386 if (pCfg->dir)
6387 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6388 else
6389 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6390
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306391 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6392 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006393 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306394 page_type = pReq->ExtPageType;
6395 extend_page = 1;
6396 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006397 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306398 page_type = pReq->Header.PageType;
6399 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006401
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306402 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6403 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6404 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6405
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306406 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306407 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006408 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306409 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6410 timeout);
6411 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6412 ret = -ETIME;
6413 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6414 "Failed Sending Config request type 0x%x, page 0x%x,"
6415 " action %d, status %xh, time left %ld\n\n",
6416 ioc->name, page_type, pReq->Header.PageNumber,
6417 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6418 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6419 goto out;
6420 if (!timeleft)
6421 issue_hard_reset = 1;
6422 goto out;
6423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006424
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306425 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6426 ret = -1;
6427 goto out;
6428 }
6429 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6430 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6431 if (ret == MPI_IOCSTATUS_SUCCESS) {
6432 if (extend_page) {
6433 pCfg->cfghdr.ehdr->ExtPageLength =
6434 le16_to_cpu(pReply->ExtPageLength);
6435 pCfg->cfghdr.ehdr->ExtPageType =
6436 pReply->ExtPageType;
6437 }
6438 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6439 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6440 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6441 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006442
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306443 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006444
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306445 if (retry_count)
6446 printk(MYIOC_s_INFO_FMT "Retry completed "
6447 "ret=0x%x timeleft=%ld\n",
6448 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006449
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306450 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6451 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006452
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306453out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006454
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306455 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6456 mutex_unlock(&ioc->mptbase_cmds.mutex);
6457 if (issue_hard_reset) {
6458 issue_hard_reset = 0;
Kei Tokunaga97009a22010-06-22 19:01:51 +09006459 printk(MYIOC_s_WARN_FMT
6460 "Issuing Reset from %s!!, doorbell=0x%08x\n",
6461 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaib3b97312010-03-18 19:14:51 +05306462 if (retry_count == 0) {
6463 if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0)
6464 retry_count++;
6465 } else
6466 mpt_HardResetHandler(ioc, CAN_SLEEP);
6467
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306468 mpt_free_msg_frame(ioc, mf);
6469 /* attempt one retry for a timed out command */
Kashyap, Desaib3b97312010-03-18 19:14:51 +05306470 if (retry_count < 2) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306471 printk(MYIOC_s_INFO_FMT
6472 "Attempting Retry Config request"
6473 " type 0x%x, page 0x%x,"
6474 " action %d\n", ioc->name, page_type,
6475 pCfg->cfghdr.hdr->PageNumber, pCfg->action);
6476 retry_count++;
6477 goto retry_config;
6478 }
6479 }
6480 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006481
Linus Torvalds1da177e2005-04-16 15:20:36 -07006482}
6483
6484/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006485/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006486 * mpt_ioc_reset - Base cleanup for hard reset
6487 * @ioc: Pointer to the adapter structure
6488 * @reset_phase: Indicates pre- or post-reset functionality
6489 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006490 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006491 */
6492static int
6493mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6494{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306495 switch (reset_phase) {
6496 case MPT_IOC_SETUP_RESET:
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306497 ioc->taskmgmt_quiesce_io = 1;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306498 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6499 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
6500 break;
6501 case MPT_IOC_PRE_RESET:
6502 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6503 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
6504 break;
6505 case MPT_IOC_POST_RESET:
6506 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6507 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
6508/* wake up mptbase_cmds */
6509 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6510 ioc->mptbase_cmds.status |=
6511 MPT_MGMT_STATUS_DID_IOCRESET;
6512 complete(&ioc->mptbase_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006513 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306514/* wake up taskmgmt_cmds */
6515 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
6516 ioc->taskmgmt_cmds.status |=
6517 MPT_MGMT_STATUS_DID_IOCRESET;
6518 complete(&ioc->taskmgmt_cmds.done);
6519 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306520 break;
6521 default:
6522 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006523 }
6524
6525 return 1; /* currently means nothing really */
6526}
6527
6528
6529#ifdef CONFIG_PROC_FS /* { */
6530/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6531/*
6532 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6533 */
6534/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006535/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006536 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6537 *
6538 * Returns 0 for success, non-zero for failure.
6539 */
6540static int
6541procmpt_create(void)
6542{
6543 struct proc_dir_entry *ent;
6544
6545 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6546 if (mpt_proc_root_dir == NULL)
6547 return -ENOTDIR;
6548
6549 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6550 if (ent)
6551 ent->read_proc = procmpt_summary_read;
6552
6553 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6554 if (ent)
6555 ent->read_proc = procmpt_version_read;
6556
6557 return 0;
6558}
6559
6560/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006561/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006562 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6563 *
6564 * Returns 0 for success, non-zero for failure.
6565 */
6566static void
6567procmpt_destroy(void)
6568{
6569 remove_proc_entry("version", mpt_proc_root_dir);
6570 remove_proc_entry("summary", mpt_proc_root_dir);
6571 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6572}
6573
6574/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006575/**
6576 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006577 * @buf: Pointer to area to write information
6578 * @start: Pointer to start pointer
6579 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006580 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006581 * @eof: Pointer to EOF integer
6582 * @data: Pointer
6583 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006584 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006585 * Returns number of characters written to process performing the read.
6586 */
6587static int
6588procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6589{
6590 MPT_ADAPTER *ioc;
6591 char *out = buf;
6592 int len;
6593
6594 if (data) {
6595 int more = 0;
6596
6597 ioc = data;
6598 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6599
6600 out += more;
6601 } else {
6602 list_for_each_entry(ioc, &ioc_list, list) {
6603 int more = 0;
6604
6605 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6606
6607 out += more;
6608 if ((out-buf) >= request)
6609 break;
6610 }
6611 }
6612
6613 len = out - buf;
6614
6615 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6616}
6617
6618/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006619/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006620 * procmpt_version_read - Handle read request from /proc/mpt/version.
6621 * @buf: Pointer to area to write information
6622 * @start: Pointer to start pointer
6623 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006624 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006625 * @eof: Pointer to EOF integer
6626 * @data: Pointer
6627 *
6628 * Returns number of characters written to process performing the read.
6629 */
6630static int
6631procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6632{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306633 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006634 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006635 char *drvname;
6636 int len;
6637
6638 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6639 len += sprintf(buf+len, " Fusion MPT base driver\n");
6640
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006641 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006642 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006643 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306644 if (MptCallbacks[cb_idx]) {
6645 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006646 case MPTSPI_DRIVER:
6647 if (!scsi++) drvname = "SPI host";
6648 break;
6649 case MPTFC_DRIVER:
6650 if (!fc++) drvname = "FC host";
6651 break;
6652 case MPTSAS_DRIVER:
6653 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006654 break;
6655 case MPTLAN_DRIVER:
6656 if (!lan++) drvname = "LAN";
6657 break;
6658 case MPTSTM_DRIVER:
6659 if (!targ++) drvname = "SCSI target";
6660 break;
6661 case MPTCTL_DRIVER:
6662 if (!ctl++) drvname = "ioctl";
6663 break;
6664 }
6665
6666 if (drvname)
6667 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6668 }
6669 }
6670
6671 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6672}
6673
6674/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006675/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006676 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6677 * @buf: Pointer to area to write information
6678 * @start: Pointer to start pointer
6679 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006680 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006681 * @eof: Pointer to EOF integer
6682 * @data: Pointer
6683 *
6684 * Returns number of characters written to process performing the read.
6685 */
6686static int
6687procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6688{
6689 MPT_ADAPTER *ioc = data;
6690 int len;
6691 char expVer[32];
6692 int sz;
6693 int p;
6694
6695 mpt_get_fw_exp_ver(expVer, ioc);
6696
6697 len = sprintf(buf, "%s:", ioc->name);
6698 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6699 len += sprintf(buf+len, " (f/w download boot flag set)");
6700// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6701// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6702
6703 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6704 ioc->facts.ProductID,
6705 ioc->prod_name);
6706 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6707 if (ioc->facts.FWImageSize)
6708 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6709 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6710 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6711 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6712
6713 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6714 ioc->facts.CurrentHostMfaHighAddr);
6715 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6716 ioc->facts.CurrentSenseBufferHighAddr);
6717
6718 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6719 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6720
6721 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6722 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6723 /*
6724 * Rounding UP to nearest 4-kB boundary here...
6725 */
6726 sz = (ioc->req_sz * ioc->req_depth) + 128;
6727 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6728 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6729 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6730 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6731 4*ioc->facts.RequestFrameSize,
6732 ioc->facts.GlobalCredits);
6733
6734 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6735 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6736 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6737 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6738 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6739 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6740 ioc->facts.CurReplyFrameSize,
6741 ioc->facts.ReplyQueueDepth);
6742
6743 len += sprintf(buf+len, " MaxDevices = %d\n",
6744 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6745 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6746
6747 /* per-port info */
6748 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6749 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6750 p+1,
6751 ioc->facts.NumberOfPorts);
6752 if (ioc->bus_type == FC) {
6753 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6754 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6755 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6756 a[5], a[4], a[3], a[2], a[1], a[0]);
6757 }
6758 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6759 ioc->fc_port_page0[p].WWNN.High,
6760 ioc->fc_port_page0[p].WWNN.Low,
6761 ioc->fc_port_page0[p].WWPN.High,
6762 ioc->fc_port_page0[p].WWPN.Low);
6763 }
6764 }
6765
6766 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6767}
6768
6769#endif /* CONFIG_PROC_FS } */
6770
6771/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6772static void
6773mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6774{
6775 buf[0] ='\0';
6776 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6777 sprintf(buf, " (Exp %02d%02d)",
6778 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6779 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6780
6781 /* insider hack! */
6782 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6783 strcat(buf, " [MDBG]");
6784 }
6785}
6786
6787/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6788/**
6789 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6790 * @ioc: Pointer to MPT_ADAPTER structure
6791 * @buffer: Pointer to buffer where IOC summary info should be written
6792 * @size: Pointer to number of bytes we wrote (set by this routine)
6793 * @len: Offset at which to start writing in buffer
6794 * @showlan: Display LAN stuff?
6795 *
6796 * This routine writes (english readable) ASCII text, which represents
6797 * a summary of IOC information, to a buffer.
6798 */
6799void
6800mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6801{
6802 char expVer[32];
6803 int y;
6804
6805 mpt_get_fw_exp_ver(expVer, ioc);
6806
6807 /*
6808 * Shorter summary of attached ioc's...
6809 */
6810 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6811 ioc->name,
6812 ioc->prod_name,
6813 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6814 ioc->facts.FWVersion.Word,
6815 expVer,
6816 ioc->facts.NumberOfPorts,
6817 ioc->req_depth);
6818
6819 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6820 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6821 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6822 a[5], a[4], a[3], a[2], a[1], a[0]);
6823 }
6824
Linus Torvalds1da177e2005-04-16 15:20:36 -07006825 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006826
6827 if (!ioc->active)
6828 y += sprintf(buffer+len+y, " (disabled)");
6829
6830 y += sprintf(buffer+len+y, "\n");
6831
6832 *size = y;
6833}
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306834/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006835 * mpt_set_taskmgmt_in_progress_flag - set flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306836 * @ioc: Pointer to MPT_ADAPTER structure
6837 *
6838 * Returns 0 for SUCCESS or -1 if FAILED.
6839 *
6840 * If -1 is return, then it was not possible to set the flags
6841 **/
6842int
6843mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6844{
6845 unsigned long flags;
6846 int retval;
6847
6848 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6849 if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
6850 (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
6851 retval = -1;
6852 goto out;
6853 }
6854 retval = 0;
6855 ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306856 ioc->taskmgmt_quiesce_io = 1;
6857 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306858 ioc->alt_ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306859 ioc->alt_ioc->taskmgmt_quiesce_io = 1;
6860 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306861 out:
6862 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6863 return retval;
6864}
6865EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
6866
6867/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006868 * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306869 * @ioc: Pointer to MPT_ADAPTER structure
6870 *
6871 **/
6872void
6873mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6874{
6875 unsigned long flags;
6876
6877 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6878 ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306879 ioc->taskmgmt_quiesce_io = 0;
6880 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306881 ioc->alt_ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306882 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
6883 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306884 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6885}
6886EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006887
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306888
6889/**
6890 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6891 * the kernel
6892 * @ioc: Pointer to MPT_ADAPTER structure
6893 *
6894 **/
6895void
6896mpt_halt_firmware(MPT_ADAPTER *ioc)
6897{
6898 u32 ioc_raw_state;
6899
6900 ioc_raw_state = mpt_GetIocState(ioc, 0);
6901
6902 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6903 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6904 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6905 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6906 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6907 } else {
6908 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6909 panic("%s: Firmware is halted due to command timeout\n",
6910 ioc->name);
6911 }
6912}
6913EXPORT_SYMBOL(mpt_halt_firmware);
6914
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306915/**
6916 * mpt_SoftResetHandler - Issues a less expensive reset
6917 * @ioc: Pointer to MPT_ADAPTER structure
6918 * @sleepFlag: Indicates if sleep or schedule must be called.
6919
6920 *
6921 * Returns 0 for SUCCESS or -1 if FAILED.
6922 *
6923 * Message Unit Reset - instructs the IOC to reset the Reply Post and
6924 * Free FIFO's. All the Message Frames on Reply Free FIFO are discarded.
6925 * All posted buffers are freed, and event notification is turned off.
6926 * IOC doesnt reply to any outstanding request. This will transfer IOC
6927 * to READY state.
6928 **/
6929int
6930mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6931{
6932 int rc;
6933 int ii;
6934 u8 cb_idx;
6935 unsigned long flags;
6936 u32 ioc_state;
6937 unsigned long time_count;
6938
6939 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n",
6940 ioc->name));
6941
6942 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
6943
6944 if (mpt_fwfault_debug)
6945 mpt_halt_firmware(ioc);
6946
6947 if (ioc_state == MPI_IOC_STATE_FAULT ||
6948 ioc_state == MPI_IOC_STATE_RESET) {
6949 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6950 "skipping, either in FAULT or RESET state!\n", ioc->name));
6951 return -1;
6952 }
6953
6954 if (ioc->bus_type == FC) {
6955 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6956 "skipping, because the bus type is FC!\n", ioc->name));
6957 return -1;
6958 }
6959
6960 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6961 if (ioc->ioc_reset_in_progress) {
6962 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6963 return -1;
6964 }
6965 ioc->ioc_reset_in_progress = 1;
6966 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6967
6968 rc = -1;
6969
6970 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6971 if (MptResetHandlers[cb_idx])
6972 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
6973 }
6974
6975 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6976 if (ioc->taskmgmt_in_progress) {
Kashyap, Desaib9a0f872010-06-17 14:42:39 +05306977 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306978 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6979 return -1;
6980 }
6981 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6982 /* Disable reply interrupts (also blocks FreeQ) */
6983 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
6984 ioc->active = 0;
6985 time_count = jiffies;
6986
6987 rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
6988
6989 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6990 if (MptResetHandlers[cb_idx])
6991 mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
6992 }
6993
6994 if (rc)
6995 goto out;
6996
6997 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
6998 if (ioc_state != MPI_IOC_STATE_READY)
6999 goto out;
7000
7001 for (ii = 0; ii < 5; ii++) {
7002 /* Get IOC facts! Allow 5 retries */
7003 rc = GetIocFacts(ioc, sleepFlag,
7004 MPT_HOSTEVENT_IOC_RECOVER);
7005 if (rc == 0)
7006 break;
7007 if (sleepFlag == CAN_SLEEP)
7008 msleep(100);
7009 else
7010 mdelay(100);
7011 }
7012 if (ii == 5)
7013 goto out;
7014
7015 rc = PrimeIocFifos(ioc);
7016 if (rc != 0)
7017 goto out;
7018
7019 rc = SendIocInit(ioc, sleepFlag);
7020 if (rc != 0)
7021 goto out;
7022
7023 rc = SendEventNotification(ioc, 1, sleepFlag);
7024 if (rc != 0)
7025 goto out;
7026
7027 if (ioc->hard_resets < -1)
7028 ioc->hard_resets++;
7029
7030 /*
7031 * At this point, we know soft reset succeeded.
7032 */
7033
7034 ioc->active = 1;
7035 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
7036
7037 out:
7038 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7039 ioc->ioc_reset_in_progress = 0;
7040 ioc->taskmgmt_quiesce_io = 0;
7041 ioc->taskmgmt_in_progress = 0;
7042 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7043
7044 if (ioc->active) { /* otherwise, hard reset coming */
7045 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7046 if (MptResetHandlers[cb_idx])
7047 mpt_signal_reset(cb_idx, ioc,
7048 MPT_IOC_POST_RESET);
7049 }
7050 }
7051
7052 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7053 "SoftResetHandler: completed (%d seconds): %s\n",
7054 ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,
7055 ((rc == 0) ? "SUCCESS" : "FAILED")));
7056
7057 return rc;
7058}
7059
7060/**
7061 * mpt_Soft_Hard_ResetHandler - Try less expensive reset
7062 * @ioc: Pointer to MPT_ADAPTER structure
7063 * @sleepFlag: Indicates if sleep or schedule must be called.
7064
7065 *
7066 * Returns 0 for SUCCESS or -1 if FAILED.
7067 * Try for softreset first, only if it fails go for expensive
7068 * HardReset.
7069 **/
7070int
7071mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag) {
7072 int ret = -1;
7073
7074 ret = mpt_SoftResetHandler(ioc, sleepFlag);
7075 if (ret == 0)
7076 return ret;
7077 ret = mpt_HardResetHandler(ioc, sleepFlag);
7078 return ret;
7079}
7080EXPORT_SYMBOL(mpt_Soft_Hard_ResetHandler);
7081
Linus Torvalds1da177e2005-04-16 15:20:36 -07007082/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7083/*
7084 * Reset Handling
7085 */
7086/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7087/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007088 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07007089 * @ioc: Pointer to MPT_ADAPTER structure
7090 * @sleepFlag: Indicates if sleep or schedule must be called.
7091 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007092 * Issues SCSI Task Management call based on input arg values.
7093 * If TaskMgmt fails, returns associated SCSI request.
7094 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07007095 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
7096 * or a non-interrupt thread. In the former, must not call schedule().
7097 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007098 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07007099 * FW reload/initialization failed.
7100 *
7101 * Returns 0 for SUCCESS or -1 if FAILED.
7102 */
7103int
7104mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
7105{
Kashyap, Desaid1306912009-08-05 12:53:51 +05307106 int rc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307107 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007108 unsigned long flags;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307109 unsigned long time_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007110
Prakash, Sathya436ace72007-07-24 15:42:08 +05307111 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007112#ifdef MFCNT
7113 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
7114 printk("MF count 0x%x !\n", ioc->mfcnt);
7115#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05307116 if (mpt_fwfault_debug)
7117 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007118
7119 /* Reset the adapter. Prevent more than 1 call to
7120 * mpt_do_ioc_recovery at any instant in time.
7121 */
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307122 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7123 if (ioc->ioc_reset_in_progress) {
7124 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007125 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007126 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307127 ioc->ioc_reset_in_progress = 1;
7128 if (ioc->alt_ioc)
7129 ioc->alt_ioc->ioc_reset_in_progress = 1;
7130 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007131
Linus Torvalds1da177e2005-04-16 15:20:36 -07007132
7133 /* The SCSI driver needs to adjust timeouts on all current
7134 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02007135 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007136 * For all other protocol drivers, this is a no-op.
7137 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05307138 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7139 if (MptResetHandlers[cb_idx]) {
7140 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
7141 if (ioc->alt_ioc)
7142 mpt_signal_reset(cb_idx, ioc->alt_ioc,
7143 MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007144 }
7145 }
7146
Kashyap, Desai2f187862009-05-29 16:52:37 +05307147 time_count = jiffies;
7148 rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
7149 if (rc != 0) {
7150 printk(KERN_WARNING MYNAM
Kei Tokunaga97009a22010-06-22 19:01:51 +09007151 ": WARNING - (%d) Cannot recover %s, doorbell=0x%08x\n",
7152 rc, ioc->name, mpt_GetIocState(ioc, 0));
Kashyap, Desai2f187862009-05-29 16:52:37 +05307153 } else {
7154 if (ioc->hard_resets < -1)
7155 ioc->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007156 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007157
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307158 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7159 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307160 ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307161 ioc->taskmgmt_in_progress = 0;
7162 if (ioc->alt_ioc) {
7163 ioc->alt_ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307164 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307165 ioc->alt_ioc->taskmgmt_in_progress = 0;
7166 }
7167 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007168
Kashyap, Desaid1306912009-08-05 12:53:51 +05307169 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7170 if (MptResetHandlers[cb_idx]) {
7171 mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
7172 if (ioc->alt_ioc)
7173 mpt_signal_reset(cb_idx,
7174 ioc->alt_ioc, MPT_IOC_POST_RESET);
7175 }
7176 }
7177
Kashyap, Desai2f187862009-05-29 16:52:37 +05307178 dtmprintk(ioc,
7179 printk(MYIOC_s_DEBUG_FMT
7180 "HardResetHandler: completed (%d seconds): %s\n", ioc->name,
7181 jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?
7182 "SUCCESS" : "FAILED")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007183
7184 return rc;
7185}
7186
Kashyap, Desai2f187862009-05-29 16:52:37 +05307187#ifdef CONFIG_FUSION_LOGGING
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007188static void
Kashyap, Desai2f187862009-05-29 16:52:37 +05307189mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007190{
Eric Moore509e5e52006-04-26 13:22:37 -06007191 char *ds = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307192 u32 evData0;
7193 int ii;
7194 u8 event;
7195 char *evStr = ioc->evStr;
7196
7197 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7198 evData0 = le32_to_cpu(pEventReply->Data[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007199
7200 switch(event) {
7201 case MPI_EVENT_NONE:
7202 ds = "None";
7203 break;
7204 case MPI_EVENT_LOG_DATA:
7205 ds = "Log Data";
7206 break;
7207 case MPI_EVENT_STATE_CHANGE:
7208 ds = "State Change";
7209 break;
7210 case MPI_EVENT_UNIT_ATTENTION:
7211 ds = "Unit Attention";
7212 break;
7213 case MPI_EVENT_IOC_BUS_RESET:
7214 ds = "IOC Bus Reset";
7215 break;
7216 case MPI_EVENT_EXT_BUS_RESET:
7217 ds = "External Bus Reset";
7218 break;
7219 case MPI_EVENT_RESCAN:
7220 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007221 break;
7222 case MPI_EVENT_LINK_STATUS_CHANGE:
7223 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
7224 ds = "Link Status(FAILURE) Change";
7225 else
7226 ds = "Link Status(ACTIVE) Change";
7227 break;
7228 case MPI_EVENT_LOOP_STATE_CHANGE:
7229 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
7230 ds = "Loop State(LIP) Change";
7231 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Kashyap, Desai2f187862009-05-29 16:52:37 +05307232 ds = "Loop State(LPE) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007233 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05307234 ds = "Loop State(LPB) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007235 break;
7236 case MPI_EVENT_LOGOUT:
7237 ds = "Logout";
7238 break;
7239 case MPI_EVENT_EVENT_CHANGE:
7240 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06007241 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007242 else
Eric Moore4f766dc2006-07-11 17:24:07 -06007243 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007244 break;
7245 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007246 {
7247 u8 ReasonCode = (u8)(evData0 >> 16);
7248 switch (ReasonCode) {
7249 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
7250 ds = "Integrated Raid: Volume Created";
7251 break;
7252 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
7253 ds = "Integrated Raid: Volume Deleted";
7254 break;
7255 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
7256 ds = "Integrated Raid: Volume Settings Changed";
7257 break;
7258 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
7259 ds = "Integrated Raid: Volume Status Changed";
7260 break;
7261 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
7262 ds = "Integrated Raid: Volume Physdisk Changed";
7263 break;
7264 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
7265 ds = "Integrated Raid: Physdisk Created";
7266 break;
7267 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
7268 ds = "Integrated Raid: Physdisk Deleted";
7269 break;
7270 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
7271 ds = "Integrated Raid: Physdisk Settings Changed";
7272 break;
7273 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
7274 ds = "Integrated Raid: Physdisk Status Changed";
7275 break;
7276 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
7277 ds = "Integrated Raid: Domain Validation Needed";
7278 break;
7279 case MPI_EVENT_RAID_RC_SMART_DATA :
7280 ds = "Integrated Raid; Smart Data";
7281 break;
7282 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
7283 ds = "Integrated Raid: Replace Action Started";
7284 break;
7285 default:
7286 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007287 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007288 }
7289 break;
7290 }
7291 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
7292 ds = "SCSI Device Status Change";
7293 break;
7294 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
7295 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007296 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007297 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007298 u8 ReasonCode = (u8)(evData0 >> 16);
7299 switch (ReasonCode) {
7300 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007301 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007302 "SAS Device Status Change: Added: "
7303 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007304 break;
7305 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06007306 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007307 "SAS Device Status Change: Deleted: "
7308 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007309 break;
7310 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06007311 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007312 "SAS Device Status Change: SMART Data: "
7313 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007314 break;
7315 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007316 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007317 "SAS Device Status Change: No Persistancy: "
7318 "id=%d channel=%d", id, channel);
7319 break;
7320 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
7321 snprintf(evStr, EVENT_DESCR_STR_SZ,
7322 "SAS Device Status Change: Unsupported Device "
7323 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007324 break;
7325 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
7326 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007327 "SAS Device Status Change: Internal Device "
7328 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007329 break;
7330 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
7331 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007332 "SAS Device Status Change: Internal Task "
7333 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007334 break;
7335 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
7336 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007337 "SAS Device Status Change: Internal Abort "
7338 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007339 break;
7340 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
7341 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007342 "SAS Device Status Change: Internal Clear "
7343 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007344 break;
7345 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
7346 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007347 "SAS Device Status Change: Internal Query "
7348 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007349 break;
7350 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007351 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007352 "SAS Device Status Change: Unknown: "
7353 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06007354 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007355 }
7356 break;
7357 }
7358 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
7359 ds = "Bus Timer Expired";
7360 break;
7361 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07007362 {
7363 u16 curr_depth = (u16)(evData0 >> 16);
7364 u8 channel = (u8)(evData0 >> 8);
7365 u8 id = (u8)(evData0);
7366
7367 snprintf(evStr, EVENT_DESCR_STR_SZ,
7368 "Queue Full: channel=%d id=%d depth=%d",
7369 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007370 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07007371 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007372 case MPI_EVENT_SAS_SES:
7373 ds = "SAS SES Event";
7374 break;
7375 case MPI_EVENT_PERSISTENT_TABLE_FULL:
7376 ds = "Persistent Table Full";
7377 break;
7378 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07007379 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007380 u8 LinkRates = (u8)(evData0 >> 8);
7381 u8 PhyNumber = (u8)(evData0);
7382 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
7383 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
7384 switch (LinkRates) {
7385 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06007386 snprintf(evStr, EVENT_DESCR_STR_SZ,
7387 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007388 " Rate Unknown",PhyNumber);
7389 break;
7390 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06007391 snprintf(evStr, EVENT_DESCR_STR_SZ,
7392 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007393 " Phy Disabled",PhyNumber);
7394 break;
7395 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06007396 snprintf(evStr, EVENT_DESCR_STR_SZ,
7397 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007398 " Failed Speed Nego",PhyNumber);
7399 break;
7400 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06007401 snprintf(evStr, EVENT_DESCR_STR_SZ,
7402 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007403 " Sata OOB Completed",PhyNumber);
7404 break;
7405 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06007406 snprintf(evStr, EVENT_DESCR_STR_SZ,
7407 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007408 " Rate 1.5 Gbps",PhyNumber);
7409 break;
7410 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06007411 snprintf(evStr, EVENT_DESCR_STR_SZ,
7412 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007413 " Rate 3.0 Gpbs",PhyNumber);
7414 break;
7415 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007416 snprintf(evStr, EVENT_DESCR_STR_SZ,
7417 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007418 break;
7419 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007420 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007421 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007422 case MPI_EVENT_SAS_DISCOVERY_ERROR:
7423 ds = "SAS Discovery Error";
7424 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007425 case MPI_EVENT_IR_RESYNC_UPDATE:
7426 {
7427 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06007428 snprintf(evStr, EVENT_DESCR_STR_SZ,
7429 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07007430 break;
7431 }
7432 case MPI_EVENT_IR2:
7433 {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307434 u8 id = (u8)(evData0);
7435 u8 channel = (u8)(evData0 >> 8);
7436 u8 phys_num = (u8)(evData0 >> 24);
Moore, Eric3a892be2006-03-14 09:14:03 -07007437 u8 ReasonCode = (u8)(evData0 >> 16);
Kashyap, Desai2f187862009-05-29 16:52:37 +05307438
Moore, Eric3a892be2006-03-14 09:14:03 -07007439 switch (ReasonCode) {
7440 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307441 snprintf(evStr, EVENT_DESCR_STR_SZ,
7442 "IR2: LD State Changed: "
7443 "id=%d channel=%d phys_num=%d",
7444 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007445 break;
7446 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307447 snprintf(evStr, EVENT_DESCR_STR_SZ,
7448 "IR2: PD 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_BAD_BLOCK_TABLE_FULL:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307453 snprintf(evStr, EVENT_DESCR_STR_SZ,
7454 "IR2: Bad Block Table Full: "
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_PD_INSERTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307459 snprintf(evStr, EVENT_DESCR_STR_SZ,
7460 "IR2: PD Inserted: "
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_REMOVED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307465 snprintf(evStr, EVENT_DESCR_STR_SZ,
7466 "IR2: PD Removed: "
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_FOREIGN_CFG_DETECTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307471 snprintf(evStr, EVENT_DESCR_STR_SZ,
7472 "IR2: Foreign CFG Detected: "
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_REBUILD_MEDIUM_ERROR:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307477 snprintf(evStr, EVENT_DESCR_STR_SZ,
7478 "IR2: Rebuild Medium Error: "
7479 "id=%d channel=%d phys_num=%d",
7480 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007481 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05307482 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
7483 snprintf(evStr, EVENT_DESCR_STR_SZ,
7484 "IR2: Dual Port Added: "
7485 "id=%d channel=%d phys_num=%d",
7486 id, channel, phys_num);
7487 break;
7488 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
7489 snprintf(evStr, EVENT_DESCR_STR_SZ,
7490 "IR2: Dual Port Removed: "
7491 "id=%d channel=%d phys_num=%d",
7492 id, channel, phys_num);
7493 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007494 default:
7495 ds = "IR2";
7496 break;
7497 }
7498 break;
7499 }
7500 case MPI_EVENT_SAS_DISCOVERY:
7501 {
7502 if (evData0)
7503 ds = "SAS Discovery: Start";
7504 else
7505 ds = "SAS Discovery: Stop";
7506 break;
7507 }
7508 case MPI_EVENT_LOG_ENTRY_ADDED:
7509 ds = "SAS Log Entry Added";
7510 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007511
Eric Moorec6c727a2007-01-29 09:44:54 -07007512 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
7513 {
7514 u8 phy_num = (u8)(evData0);
7515 u8 port_num = (u8)(evData0 >> 8);
7516 u8 port_width = (u8)(evData0 >> 16);
7517 u8 primative = (u8)(evData0 >> 24);
7518 snprintf(evStr, EVENT_DESCR_STR_SZ,
7519 "SAS Broadcase Primative: phy=%d port=%d "
7520 "width=%d primative=0x%02x",
7521 phy_num, port_num, port_width, primative);
7522 break;
7523 }
7524
7525 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7526 {
7527 u8 reason = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007528
Kashyap, Desai2f187862009-05-29 16:52:37 +05307529 switch (reason) {
7530 case MPI_EVENT_SAS_INIT_RC_ADDED:
7531 ds = "SAS Initiator Status Change: Added";
7532 break;
7533 case MPI_EVENT_SAS_INIT_RC_REMOVED:
7534 ds = "SAS Initiator Status Change: Deleted";
7535 break;
7536 default:
7537 ds = "SAS Initiator Status Change";
7538 break;
7539 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007540 break;
7541 }
7542
7543 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7544 {
7545 u8 max_init = (u8)(evData0);
7546 u8 current_init = (u8)(evData0 >> 8);
7547
7548 snprintf(evStr, EVENT_DESCR_STR_SZ,
7549 "SAS Initiator Device Table Overflow: max initiators=%02d "
7550 "current initators=%02d",
7551 max_init, current_init);
7552 break;
7553 }
7554 case MPI_EVENT_SAS_SMP_ERROR:
7555 {
7556 u8 status = (u8)(evData0);
7557 u8 port_num = (u8)(evData0 >> 8);
7558 u8 result = (u8)(evData0 >> 16);
7559
7560 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7561 snprintf(evStr, EVENT_DESCR_STR_SZ,
7562 "SAS SMP Error: port=%d result=0x%02x",
7563 port_num, result);
7564 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7565 snprintf(evStr, EVENT_DESCR_STR_SZ,
7566 "SAS SMP Error: port=%d : CRC Error",
7567 port_num);
7568 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7569 snprintf(evStr, EVENT_DESCR_STR_SZ,
7570 "SAS SMP Error: port=%d : Timeout",
7571 port_num);
7572 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7573 snprintf(evStr, EVENT_DESCR_STR_SZ,
7574 "SAS SMP Error: port=%d : No Destination",
7575 port_num);
7576 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7577 snprintf(evStr, EVENT_DESCR_STR_SZ,
7578 "SAS SMP Error: port=%d : Bad Destination",
7579 port_num);
7580 else
7581 snprintf(evStr, EVENT_DESCR_STR_SZ,
7582 "SAS SMP Error: port=%d : status=0x%02x",
7583 port_num, status);
7584 break;
7585 }
7586
Kashyap, Desai2f187862009-05-29 16:52:37 +05307587 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
7588 {
7589 u8 reason = (u8)(evData0);
7590
7591 switch (reason) {
7592 case MPI_EVENT_SAS_EXP_RC_ADDED:
7593 ds = "Expander Status Change: Added";
7594 break;
7595 case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
7596 ds = "Expander Status Change: Deleted";
7597 break;
7598 default:
7599 ds = "Expander Status Change";
7600 break;
7601 }
7602 break;
7603 }
7604
Linus Torvalds1da177e2005-04-16 15:20:36 -07007605 /*
7606 * MPT base "custom" events may be added here...
7607 */
7608 default:
7609 ds = "Unknown";
7610 break;
7611 }
Eric Moore509e5e52006-04-26 13:22:37 -06007612 if (ds)
7613 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007614
Kashyap, Desai2f187862009-05-29 16:52:37 +05307615
7616 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7617 "MPT event:(%02Xh) : %s\n",
7618 ioc->name, event, evStr));
7619
7620 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
7621 ": Event data:\n"));
7622 for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
7623 devtverboseprintk(ioc, printk(" %08x",
7624 le32_to_cpu(pEventReply->Data[ii])));
7625 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
7626}
7627#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007628/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007629/**
7630 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007631 * @ioc: Pointer to MPT_ADAPTER structure
7632 * @pEventReply: Pointer to EventNotification reply frame
7633 * @evHandlers: Pointer to integer, number of event handlers
7634 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007635 * Routes a received EventNotificationReply to all currently registered
7636 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007637 * Returns sum of event handlers return values.
7638 */
7639static int
7640ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7641{
7642 u16 evDataLen;
7643 u32 evData0 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007644 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307645 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007646 int r = 0;
7647 int handlers = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007648 u8 event;
7649
7650 /*
7651 * Do platform normalization of values
7652 */
7653 event = le32_to_cpu(pEventReply->Event) & 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007654 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7655 if (evDataLen) {
7656 evData0 = le32_to_cpu(pEventReply->Data[0]);
7657 }
7658
Prakash, Sathya436ace72007-07-24 15:42:08 +05307659#ifdef CONFIG_FUSION_LOGGING
Kashyap, Desai2f187862009-05-29 16:52:37 +05307660 if (evDataLen)
7661 mpt_display_event_info(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007662#endif
7663
7664 /*
7665 * Do general / base driver event processing
7666 */
7667 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007668 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7669 if (evDataLen) {
7670 u8 evState = evData0 & 0xFF;
7671
7672 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7673
7674 /* Update EventState field in cached IocFacts */
7675 if (ioc->facts.Function) {
7676 ioc->facts.EventState = evState;
7677 }
7678 }
7679 break;
Moore, Ericece50912006-01-16 18:53:19 -07007680 case MPI_EVENT_INTEGRATED_RAID:
7681 mptbase_raid_process_event_data(ioc,
7682 (MpiEventDataRaid_t *)pEventReply->Data);
7683 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007684 default:
7685 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007686 }
7687
7688 /*
7689 * Should this event be logged? Events are written sequentially.
7690 * When buffer is full, start again at the top.
7691 */
7692 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7693 int idx;
7694
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007695 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007696
7697 ioc->events[idx].event = event;
7698 ioc->events[idx].eventContext = ioc->eventContext;
7699
7700 for (ii = 0; ii < 2; ii++) {
7701 if (ii < evDataLen)
7702 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7703 else
7704 ioc->events[idx].data[ii] = 0;
7705 }
7706
7707 ioc->eventContext++;
7708 }
7709
7710
7711 /*
7712 * Call each currently registered protocol event handler.
7713 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007714 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307715 if (MptEvHandlers[cb_idx]) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307716 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7717 "Routing Event to event handler #%d\n",
7718 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307719 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007720 handlers++;
7721 }
7722 }
7723 /* FIXME? Examine results here? */
7724
7725 /*
7726 * If needed, send (a single) EventAck.
7727 */
7728 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307729 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007730 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007731 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307732 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007733 ioc->name, ii));
7734 }
7735 }
7736
7737 *evHandlers = handlers;
7738 return r;
7739}
7740
7741/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007742/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007743 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7744 * @ioc: Pointer to MPT_ADAPTER structure
7745 * @log_info: U32 LogInfo reply word from the IOC
7746 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007747 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007748 */
7749static void
7750mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7751{
Eric Moore7c431e52007-06-13 16:34:36 -06007752 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007753
Eric Moore7c431e52007-06-13 16:34:36 -06007754 switch (log_info & 0xFF000000) {
7755 case MPI_IOCLOGINFO_FC_INIT_BASE:
7756 desc = "FCP Initiator";
7757 break;
7758 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7759 desc = "FCP Target";
7760 break;
7761 case MPI_IOCLOGINFO_FC_LAN_BASE:
7762 desc = "LAN";
7763 break;
7764 case MPI_IOCLOGINFO_FC_MSG_BASE:
7765 desc = "MPI Message Layer";
7766 break;
7767 case MPI_IOCLOGINFO_FC_LINK_BASE:
7768 desc = "FC Link";
7769 break;
7770 case MPI_IOCLOGINFO_FC_CTX_BASE:
7771 desc = "Context Manager";
7772 break;
7773 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7774 desc = "Invalid Field Offset";
7775 break;
7776 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7777 desc = "State Change Info";
7778 break;
7779 }
7780
7781 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7782 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007783}
7784
7785/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007786/**
Moore, Eric335a9412006-01-17 17:06:23 -07007787 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007788 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007789 * @log_info: U32 LogInfo word from the IOC
7790 *
7791 * Refer to lsi/sp_log.h.
7792 */
7793static void
Moore, Eric335a9412006-01-17 17:06:23 -07007794mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007795{
7796 u32 info = log_info & 0x00FF0000;
7797 char *desc = "unknown";
7798
7799 switch (info) {
7800 case 0x00010000:
7801 desc = "bug! MID not found";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007802 break;
7803
7804 case 0x00020000:
7805 desc = "Parity Error";
7806 break;
7807
7808 case 0x00030000:
7809 desc = "ASYNC Outbound Overrun";
7810 break;
7811
7812 case 0x00040000:
7813 desc = "SYNC Offset Error";
7814 break;
7815
7816 case 0x00050000:
7817 desc = "BM Change";
7818 break;
7819
7820 case 0x00060000:
7821 desc = "Msg In Overflow";
7822 break;
7823
7824 case 0x00070000:
7825 desc = "DMA Error";
7826 break;
7827
7828 case 0x00080000:
7829 desc = "Outbound DMA Overrun";
7830 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007831
Linus Torvalds1da177e2005-04-16 15:20:36 -07007832 case 0x00090000:
7833 desc = "Task Management";
7834 break;
7835
7836 case 0x000A0000:
7837 desc = "Device Problem";
7838 break;
7839
7840 case 0x000B0000:
7841 desc = "Invalid Phase Change";
7842 break;
7843
7844 case 0x000C0000:
7845 desc = "Untagged Table Size";
7846 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007847
Linus Torvalds1da177e2005-04-16 15:20:36 -07007848 }
7849
7850 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7851}
7852
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007853/* strings for sas loginfo */
7854 static char *originator_str[] = {
7855 "IOP", /* 00h */
7856 "PL", /* 01h */
7857 "IR" /* 02h */
7858 };
7859 static char *iop_code_str[] = {
7860 NULL, /* 00h */
7861 "Invalid SAS Address", /* 01h */
7862 NULL, /* 02h */
7863 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007864 "Diag Message Error", /* 04h */
7865 "Task Terminated", /* 05h */
7866 "Enclosure Management", /* 06h */
7867 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007868 };
7869 static char *pl_code_str[] = {
7870 NULL, /* 00h */
7871 "Open Failure", /* 01h */
7872 "Invalid Scatter Gather List", /* 02h */
7873 "Wrong Relative Offset or Frame Length", /* 03h */
7874 "Frame Transfer Error", /* 04h */
7875 "Transmit Frame Connected Low", /* 05h */
7876 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7877 "SATA Read Log Receive Data Error", /* 07h */
7878 "SATA NCQ Fail All Commands After Error", /* 08h */
7879 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7880 "Receive Frame Invalid Message", /* 0Ah */
7881 "Receive Context Message Valid Error", /* 0Bh */
7882 "Receive Frame Current Frame Error", /* 0Ch */
7883 "SATA Link Down", /* 0Dh */
7884 "Discovery SATA Init W IOS", /* 0Eh */
7885 "Config Invalid Page", /* 0Fh */
7886 "Discovery SATA Init Timeout", /* 10h */
7887 "Reset", /* 11h */
7888 "Abort", /* 12h */
7889 "IO Not Yet Executed", /* 13h */
7890 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007891 "Persistent Reservation Out Not Affiliation "
7892 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007893 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007894 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007895 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007896 NULL, /* 19h */
7897 NULL, /* 1Ah */
7898 NULL, /* 1Bh */
7899 NULL, /* 1Ch */
7900 NULL, /* 1Dh */
7901 NULL, /* 1Eh */
7902 NULL, /* 1Fh */
7903 "Enclosure Management" /* 20h */
7904 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007905 static char *ir_code_str[] = {
7906 "Raid Action Error", /* 00h */
7907 NULL, /* 00h */
7908 NULL, /* 01h */
7909 NULL, /* 02h */
7910 NULL, /* 03h */
7911 NULL, /* 04h */
7912 NULL, /* 05h */
7913 NULL, /* 06h */
7914 NULL /* 07h */
7915 };
7916 static char *raid_sub_code_str[] = {
7917 NULL, /* 00h */
7918 "Volume Creation Failed: Data Passed too "
7919 "Large", /* 01h */
7920 "Volume Creation Failed: Duplicate Volumes "
7921 "Attempted", /* 02h */
7922 "Volume Creation Failed: Max Number "
7923 "Supported Volumes Exceeded", /* 03h */
7924 "Volume Creation Failed: DMA Error", /* 04h */
7925 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7926 "Volume Creation Failed: Error Reading "
7927 "MFG Page 4", /* 06h */
7928 "Volume Creation Failed: Creating Internal "
7929 "Structures", /* 07h */
7930 NULL, /* 08h */
7931 NULL, /* 09h */
7932 NULL, /* 0Ah */
7933 NULL, /* 0Bh */
7934 NULL, /* 0Ch */
7935 NULL, /* 0Dh */
7936 NULL, /* 0Eh */
7937 NULL, /* 0Fh */
7938 "Activation failed: Already Active Volume", /* 10h */
7939 "Activation failed: Unsupported Volume Type", /* 11h */
7940 "Activation failed: Too Many Active Volumes", /* 12h */
7941 "Activation failed: Volume ID in Use", /* 13h */
7942 "Activation failed: Reported Failure", /* 14h */
7943 "Activation failed: Importing a Volume", /* 15h */
7944 NULL, /* 16h */
7945 NULL, /* 17h */
7946 NULL, /* 18h */
7947 NULL, /* 19h */
7948 NULL, /* 1Ah */
7949 NULL, /* 1Bh */
7950 NULL, /* 1Ch */
7951 NULL, /* 1Dh */
7952 NULL, /* 1Eh */
7953 NULL, /* 1Fh */
7954 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7955 "Phys Disk failed: Data Passed too Large", /* 21h */
7956 "Phys Disk failed: DMA Error", /* 22h */
7957 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7958 "Phys Disk failed: Creating Phys Disk Config "
7959 "Page", /* 24h */
7960 NULL, /* 25h */
7961 NULL, /* 26h */
7962 NULL, /* 27h */
7963 NULL, /* 28h */
7964 NULL, /* 29h */
7965 NULL, /* 2Ah */
7966 NULL, /* 2Bh */
7967 NULL, /* 2Ch */
7968 NULL, /* 2Dh */
7969 NULL, /* 2Eh */
7970 NULL, /* 2Fh */
7971 "Compatibility Error: IR Disabled", /* 30h */
7972 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7973 "Compatibility Error: Device not Direct Access "
7974 "Device ", /* 32h */
7975 "Compatibility Error: Removable Device Found", /* 33h */
7976 "Compatibility Error: Device SCSI Version not "
7977 "2 or Higher", /* 34h */
7978 "Compatibility Error: SATA Device, 48 BIT LBA "
7979 "not Supported", /* 35h */
7980 "Compatibility Error: Device doesn't have "
7981 "512 Byte Block Sizes", /* 36h */
7982 "Compatibility Error: Volume Type Check Failed", /* 37h */
7983 "Compatibility Error: Volume Type is "
7984 "Unsupported by FW", /* 38h */
7985 "Compatibility Error: Disk Drive too Small for "
7986 "use in Volume", /* 39h */
7987 "Compatibility Error: Phys Disk for Create "
7988 "Volume not Found", /* 3Ah */
7989 "Compatibility Error: Too Many or too Few "
7990 "Disks for Volume Type", /* 3Bh */
7991 "Compatibility Error: Disk stripe Sizes "
7992 "Must be 64KB", /* 3Ch */
7993 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7994 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007995
7996/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007997/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007998 * mpt_sas_log_info - Log information returned from SAS IOC.
7999 * @ioc: Pointer to MPT_ADAPTER structure
8000 * @log_info: U32 LogInfo reply word from the IOC
8001 *
8002 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008003 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008004static void
8005mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
8006{
8007union loginfo_type {
8008 u32 loginfo;
8009 struct {
8010 u32 subcode:16;
8011 u32 code:8;
8012 u32 originator:4;
8013 u32 bus_type:4;
8014 }dw;
8015};
8016 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07008017 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008018 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07008019 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008020
8021 sas_loginfo.loginfo = log_info;
8022 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008023 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008024 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07008025
8026 originator_desc = originator_str[sas_loginfo.dw.originator];
8027
8028 switch (sas_loginfo.dw.originator) {
8029
8030 case 0: /* IOP */
8031 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008032 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008033 code_desc = iop_code_str[sas_loginfo.dw.code];
8034 break;
8035 case 1: /* PL */
8036 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008037 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008038 code_desc = pl_code_str[sas_loginfo.dw.code];
8039 break;
8040 case 2: /* IR */
8041 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008042 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008043 break;
8044 code_desc = ir_code_str[sas_loginfo.dw.code];
8045 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008046 ARRAY_SIZE(raid_sub_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008047 break;
8048 if (sas_loginfo.dw.code == 0)
8049 sub_code_desc =
8050 raid_sub_code_str[sas_loginfo.dw.subcode];
8051 break;
8052 default:
8053 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008054 }
8055
Eric Moorec6c727a2007-01-29 09:44:54 -07008056 if (sub_code_desc != NULL)
8057 printk(MYIOC_s_INFO_FMT
8058 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
8059 " SubCode={%s}\n",
8060 ioc->name, log_info, originator_desc, code_desc,
8061 sub_code_desc);
8062 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008063 printk(MYIOC_s_INFO_FMT
8064 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
8065 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008066 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008067 sas_loginfo.dw.subcode);
8068 else
8069 printk(MYIOC_s_INFO_FMT
8070 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
8071 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008072 ioc->name, log_info, originator_desc,
8073 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008074}
8075
Linus Torvalds1da177e2005-04-16 15:20:36 -07008076/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008077/**
Eric Moorec6c727a2007-01-29 09:44:54 -07008078 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
8079 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08008080 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07008081 * @mf: Pointer to MPT request frame
8082 *
8083 * Refer to lsi/mpi.h.
8084 **/
8085static void
8086mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
8087{
8088 Config_t *pReq = (Config_t *)mf;
8089 char extend_desc[EVENT_DESCR_STR_SZ];
8090 char *desc = NULL;
8091 u32 form;
8092 u8 page_type;
8093
8094 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
8095 page_type = pReq->ExtPageType;
8096 else
8097 page_type = pReq->Header.PageType;
8098
8099 /*
8100 * ignore invalid page messages for GET_NEXT_HANDLE
8101 */
8102 form = le32_to_cpu(pReq->PageAddress);
8103 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
8104 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
8105 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
8106 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
8107 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
8108 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
8109 return;
8110 }
8111 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
8112 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
8113 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
8114 return;
8115 }
8116
8117 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
8118 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
8119 page_type, pReq->Header.PageNumber, pReq->Action, form);
8120
8121 switch (ioc_status) {
8122
8123 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8124 desc = "Config Page Invalid Action";
8125 break;
8126
8127 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8128 desc = "Config Page Invalid Type";
8129 break;
8130
8131 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8132 desc = "Config Page Invalid Page";
8133 break;
8134
8135 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8136 desc = "Config Page Invalid Data";
8137 break;
8138
8139 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8140 desc = "Config Page No Defaults";
8141 break;
8142
8143 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
8144 desc = "Config Page Can't Commit";
8145 break;
8146 }
8147
8148 if (!desc)
8149 return;
8150
Eric Moore29dd3602007-09-14 18:46:51 -06008151 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
8152 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07008153}
8154
8155/**
8156 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07008157 * @ioc: Pointer to MPT_ADAPTER structure
8158 * @ioc_status: U32 IOCStatus word from IOC
8159 * @mf: Pointer to MPT request frame
8160 *
8161 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008162 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07008163static void
Eric Moorec6c727a2007-01-29 09:44:54 -07008164mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008165{
8166 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06008167 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008168
8169 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07008170
8171/****************************************************************************/
8172/* Common IOCStatus values for all replies */
8173/****************************************************************************/
8174
Linus Torvalds1da177e2005-04-16 15:20:36 -07008175 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
8176 desc = "Invalid Function";
8177 break;
8178
8179 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
8180 desc = "Busy";
8181 break;
8182
8183 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
8184 desc = "Invalid SGL";
8185 break;
8186
8187 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
8188 desc = "Internal Error";
8189 break;
8190
8191 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
8192 desc = "Reserved";
8193 break;
8194
8195 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
8196 desc = "Insufficient Resources";
8197 break;
8198
8199 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
8200 desc = "Invalid Field";
8201 break;
8202
8203 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
8204 desc = "Invalid State";
8205 break;
8206
Eric Moorec6c727a2007-01-29 09:44:54 -07008207/****************************************************************************/
8208/* Config IOCStatus values */
8209/****************************************************************************/
8210
Linus Torvalds1da177e2005-04-16 15:20:36 -07008211 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8212 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8213 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8214 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8215 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8216 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008217 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008218 break;
8219
Eric Moorec6c727a2007-01-29 09:44:54 -07008220/****************************************************************************/
8221/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
8222/* */
8223/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
8224/* */
8225/****************************************************************************/
8226
Linus Torvalds1da177e2005-04-16 15:20:36 -07008227 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008228 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008229 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
8230 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
8231 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
8232 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008233 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008234 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008235 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008236 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008237 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008238 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07008239 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008240 break;
8241
Eric Moorec6c727a2007-01-29 09:44:54 -07008242/****************************************************************************/
8243/* SCSI Target values */
8244/****************************************************************************/
8245
8246 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
8247 desc = "Target: Priority IO";
8248 break;
8249
8250 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
8251 desc = "Target: Invalid Port";
8252 break;
8253
8254 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
8255 desc = "Target Invalid IO Index:";
8256 break;
8257
8258 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
8259 desc = "Target: Aborted";
8260 break;
8261
8262 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
8263 desc = "Target: No Conn Retryable";
8264 break;
8265
8266 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
8267 desc = "Target: No Connection";
8268 break;
8269
8270 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
8271 desc = "Target: Transfer Count Mismatch";
8272 break;
8273
8274 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
8275 desc = "Target: STS Data not Sent";
8276 break;
8277
8278 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
8279 desc = "Target: Data Offset Error";
8280 break;
8281
8282 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
8283 desc = "Target: Too Much Write Data";
8284 break;
8285
8286 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
8287 desc = "Target: IU Too Short";
8288 break;
8289
8290 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
8291 desc = "Target: ACK NAK Timeout";
8292 break;
8293
8294 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
8295 desc = "Target: Nak Received";
8296 break;
8297
8298/****************************************************************************/
8299/* Fibre Channel Direct Access values */
8300/****************************************************************************/
8301
8302 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
8303 desc = "FC: Aborted";
8304 break;
8305
8306 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
8307 desc = "FC: RX ID Invalid";
8308 break;
8309
8310 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
8311 desc = "FC: DID Invalid";
8312 break;
8313
8314 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
8315 desc = "FC: Node Logged Out";
8316 break;
8317
8318 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
8319 desc = "FC: Exchange Canceled";
8320 break;
8321
8322/****************************************************************************/
8323/* LAN values */
8324/****************************************************************************/
8325
8326 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
8327 desc = "LAN: Device not Found";
8328 break;
8329
8330 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
8331 desc = "LAN: Device Failure";
8332 break;
8333
8334 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
8335 desc = "LAN: Transmit Error";
8336 break;
8337
8338 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
8339 desc = "LAN: Transmit Aborted";
8340 break;
8341
8342 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
8343 desc = "LAN: Receive Error";
8344 break;
8345
8346 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
8347 desc = "LAN: Receive Aborted";
8348 break;
8349
8350 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
8351 desc = "LAN: Partial Packet";
8352 break;
8353
8354 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
8355 desc = "LAN: Canceled";
8356 break;
8357
8358/****************************************************************************/
8359/* Serial Attached SCSI values */
8360/****************************************************************************/
8361
8362 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
8363 desc = "SAS: SMP Request Failed";
8364 break;
8365
8366 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
8367 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07008368 break;
8369
8370 default:
8371 desc = "Others";
8372 break;
8373 }
Eric Moorec6c727a2007-01-29 09:44:54 -07008374
8375 if (!desc)
8376 return;
8377
Eric Moore29dd3602007-09-14 18:46:51 -06008378 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
8379 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008380}
8381
8382/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008383EXPORT_SYMBOL(mpt_attach);
8384EXPORT_SYMBOL(mpt_detach);
8385#ifdef CONFIG_PM
8386EXPORT_SYMBOL(mpt_resume);
8387EXPORT_SYMBOL(mpt_suspend);
8388#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07008389EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008390EXPORT_SYMBOL(mpt_register);
8391EXPORT_SYMBOL(mpt_deregister);
8392EXPORT_SYMBOL(mpt_event_register);
8393EXPORT_SYMBOL(mpt_event_deregister);
8394EXPORT_SYMBOL(mpt_reset_register);
8395EXPORT_SYMBOL(mpt_reset_deregister);
8396EXPORT_SYMBOL(mpt_device_driver_register);
8397EXPORT_SYMBOL(mpt_device_driver_deregister);
8398EXPORT_SYMBOL(mpt_get_msg_frame);
8399EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05308400EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008401EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008402EXPORT_SYMBOL(mpt_send_handshake_request);
8403EXPORT_SYMBOL(mpt_verify_adapter);
8404EXPORT_SYMBOL(mpt_GetIocState);
8405EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008406EXPORT_SYMBOL(mpt_HardResetHandler);
8407EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008408EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008409EXPORT_SYMBOL(mpt_alloc_fw_memory);
8410EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02008411EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07008412EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008413
Linus Torvalds1da177e2005-04-16 15:20:36 -07008414/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008415/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008416 * fusion_init - Fusion MPT base driver initialization routine.
8417 *
8418 * Returns 0 for success, non-zero for failure.
8419 */
8420static int __init
8421fusion_init(void)
8422{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308423 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008424
8425 show_mptmod_ver(my_NAME, my_VERSION);
8426 printk(KERN_INFO COPYRIGHT "\n");
8427
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308428 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
8429 MptCallbacks[cb_idx] = NULL;
8430 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
8431 MptEvHandlers[cb_idx] = NULL;
8432 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008433 }
8434
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008435 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07008436 * EventNotification handling.
8437 */
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05308438 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008439
8440 /* Register for hard reset handling callbacks.
8441 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05308442 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008443
8444#ifdef CONFIG_PROC_FS
8445 (void) procmpt_create();
8446#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008447 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008448}
8449
8450/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008451/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008452 * fusion_exit - Perform driver unload cleanup.
8453 *
8454 * This routine frees all resources associated with each MPT adapter
8455 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
8456 */
8457static void __exit
8458fusion_exit(void)
8459{
8460
Linus Torvalds1da177e2005-04-16 15:20:36 -07008461 mpt_reset_deregister(mpt_base_index);
8462
8463#ifdef CONFIG_PROC_FS
8464 procmpt_destroy();
8465#endif
8466}
8467
Linus Torvalds1da177e2005-04-16 15:20:36 -07008468module_init(fusion_init);
8469module_exit(fusion_exit);