blob: 49005e151058d65497984cb6e49acd6a29a05d2b [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 ioc->pcidev = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301775 spin_lock_init(&ioc->taskmgmt_lock);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05301776 mutex_init(&ioc->internal_cmds.mutex);
1777 init_completion(&ioc->internal_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301778 mutex_init(&ioc->mptbase_cmds.mutex);
1779 init_completion(&ioc->mptbase_cmds.done);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301780 mutex_init(&ioc->taskmgmt_cmds.mutex);
1781 init_completion(&ioc->taskmgmt_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301782
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 /* Initialize the event logging.
1784 */
1785 ioc->eventTypes = 0; /* None */
1786 ioc->eventContext = 0;
1787 ioc->eventLogSize = 0;
1788 ioc->events = NULL;
1789
1790#ifdef MFCNT
1791 ioc->mfcnt = 0;
1792#endif
1793
Kashyap, Desai2f187862009-05-29 16:52:37 +05301794 ioc->sh = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 ioc->cached_fw = NULL;
1796
1797 /* Initilize SCSI Config Data structure
1798 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001799 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800
Michael Reed05e8ec12006-01-13 14:31:54 -06001801 /* Initialize the fc rport list head.
1802 */
1803 INIT_LIST_HEAD(&ioc->fc_rports);
1804
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 /* Find lookup slot. */
1806 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001807
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301808
1809 /* Initialize workqueue */
1810 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301811
Kashyap, Desai2f187862009-05-29 16:52:37 +05301812 snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN,
Kay Sieversaab0de22008-05-02 06:02:41 +02001813 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301814 ioc->reset_work_q =
1815 create_singlethread_workqueue(ioc->reset_work_q_name);
1816 if (!ioc->reset_work_q) {
1817 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1818 ioc->name);
1819 pci_release_selected_regions(pdev, ioc->bars);
1820 kfree(ioc);
1821 return -ENOMEM;
1822 }
1823
Eric Moore29dd3602007-09-14 18:46:51 -06001824 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1825 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301827 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1828 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1829
1830 switch (pdev->device)
1831 {
1832 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1833 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1834 ioc->errata_flag_1064 = 1;
1835 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1836 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1837 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1838 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301840 break;
1841
1842 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 /* 929X Chip Fix. Set Split transactions level
1845 * for PCIX. Set MOST bits to zero.
1846 */
1847 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1848 pcixcmd &= 0x8F;
1849 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1850 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 /* 929XL Chip Fix. Set MMRBC to 0x08.
1852 */
1853 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1854 pcixcmd |= 0x08;
1855 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1856 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301858 break;
1859
1860 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 /* 919X Chip Fix. Set Split transactions level
1862 * for PCIX. Set MOST bits to zero.
1863 */
1864 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1865 pcixcmd &= 0x8F;
1866 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001867 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301868 break;
1869
1870 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 /* 1030 Chip Fix. Disable Split transactions
1872 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1873 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 if (revision < C0_1030) {
1875 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1876 pcixcmd &= 0x8F;
1877 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1878 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301879
1880 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001881 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301882 break;
1883
1884 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1885 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001886 ioc->errata_flag_1064 = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301887 ioc->bus_type = SAS;
1888 break;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301889
1890 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1891 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1892 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001893 ioc->bus_type = SAS;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301894 break;
Eric Moore87cf8982006-06-27 16:09:26 -06001895 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301897
Kashyap, Desaie3829682009-01-08 14:27:16 +05301898 switch (ioc->bus_type) {
1899
1900 case SAS:
1901 ioc->msi_enable = mpt_msi_enable_sas;
1902 break;
1903
1904 case SPI:
1905 ioc->msi_enable = mpt_msi_enable_spi;
1906 break;
1907
1908 case FC:
1909 ioc->msi_enable = mpt_msi_enable_fc;
1910 break;
1911
1912 default:
1913 ioc->msi_enable = 0;
1914 break;
1915 }
Kashyap, Desai8ce13de2010-06-17 14:35:46 +05301916
1917 ioc->fw_events_off = 1;
1918
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001919 if (ioc->errata_flag_1064)
1920 pci_disable_io_access(pdev);
1921
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 spin_lock_init(&ioc->FreeQlock);
1923
1924 /* Disable all! */
1925 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1926 ioc->active = 0;
1927 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1928
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301929 /* Set IOC ptr in the pcidev's driver data. */
1930 pci_set_drvdata(ioc->pcidev, ioc);
1931
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 /* Set lookup ptr. */
1933 list_add_tail(&ioc->list, &ioc_list);
1934
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001935 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 */
1937 mpt_detect_bound_ports(ioc, pdev);
1938
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301939 INIT_LIST_HEAD(&ioc->fw_event_list);
1940 spin_lock_init(&ioc->fw_event_lock);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301941 snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301942 ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
1943
James Bottomleyc92f2222006-03-01 09:02:49 -06001944 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1945 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001946 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1947 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001948
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001950 if (ioc->alt_ioc)
1951 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301952 iounmap(ioc->memmap);
1953 if (r != -5)
1954 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301955
1956 destroy_workqueue(ioc->reset_work_q);
1957 ioc->reset_work_q = NULL;
1958
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 kfree(ioc);
1960 pci_set_drvdata(pdev, NULL);
1961 return r;
1962 }
1963
1964 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001965 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301966 if(MptDeviceDriverHandlers[cb_idx] &&
1967 MptDeviceDriverHandlers[cb_idx]->probe) {
1968 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 }
1970 }
1971
1972#ifdef CONFIG_PROC_FS
1973 /*
1974 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1975 */
1976 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1977 if (dent) {
1978 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1979 if (ent) {
1980 ent->read_proc = procmpt_iocinfo_read;
1981 ent->data = ioc;
1982 }
1983 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1984 if (ent) {
1985 ent->read_proc = procmpt_summary_read;
1986 ent->data = ioc;
1987 }
1988 }
1989#endif
1990
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301991 if (!ioc->alt_ioc)
1992 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1993 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1994
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 return 0;
1996}
1997
1998/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001999/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002000 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 */
2003
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002004void
2005mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006{
2007 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2008 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302009 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302010 unsigned long flags;
2011 struct workqueue_struct *wq;
2012
2013 /*
2014 * Stop polling ioc for fault condition
2015 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302016 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302017 wq = ioc->reset_work_q;
2018 ioc->reset_work_q = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302019 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302020 cancel_delayed_work(&ioc->fault_reset_work);
2021 destroy_workqueue(wq);
2022
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05302023 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2024 wq = ioc->fw_event_q;
2025 ioc->fw_event_q = NULL;
2026 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2027 destroy_workqueue(wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028
2029 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2030 remove_proc_entry(pname, NULL);
2031 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2032 remove_proc_entry(pname, NULL);
2033 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2034 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002035
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002037 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302038 if(MptDeviceDriverHandlers[cb_idx] &&
2039 MptDeviceDriverHandlers[cb_idx]->remove) {
2040 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 }
2042 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002043
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 /* Disable interrupts! */
2045 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2046
2047 ioc->active = 0;
2048 synchronize_irq(pdev->irq);
2049
2050 /* Clear any lingering interrupt */
2051 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2052
2053 CHIPREG_READ32(&ioc->chip->IntStatus);
2054
2055 mpt_adapter_dispose(ioc);
2056
2057 pci_set_drvdata(pdev, NULL);
2058}
2059
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060/**************************************************************************
2061 * Power Management
2062 */
2063#ifdef CONFIG_PM
2064/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002065/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002066 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002067 * @pdev: Pointer to pci_dev structure
2068 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002070int
2071mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072{
2073 u32 device_state;
2074 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302076 device_state = pci_choose_state(pdev, state);
2077 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2078 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2079 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080
2081 /* put ioc into READY_STATE */
2082 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2083 printk(MYIOC_s_ERR_FMT
2084 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2085 }
2086
2087 /* disable interrupts */
2088 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2089 ioc->active = 0;
2090
2091 /* Clear any lingering interrupt */
2092 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2093
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302094 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002095 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302096 pci_disable_msi(ioc->pcidev);
2097 ioc->pci_irq = -1;
2098 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302100 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 return 0;
2103}
2104
2105/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002106/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002107 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002108 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002110int
2111mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112{
2113 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2114 u32 device_state = pdev->current_state;
2115 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302116 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002117
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302118 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2119 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2120 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302122 pci_set_power_state(pdev, PCI_D0);
2123 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302125 ioc->pcidev = pdev;
2126 err = mpt_mapresources(ioc);
2127 if (err)
2128 return err;
2129
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302130 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2131 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2132 ioc->add_sge = &mpt_add_sge_64bit_1078;
2133 else
2134 ioc->add_sge = &mpt_add_sge_64bit;
2135 ioc->add_chain = &mpt_add_chain_64bit;
2136 ioc->sg_addr_size = 8;
2137 } else {
2138
2139 ioc->add_sge = &mpt_add_sge;
2140 ioc->add_chain = &mpt_add_chain;
2141 ioc->sg_addr_size = 4;
2142 }
2143 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2144
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302145 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2146 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2147 CHIPREG_READ32(&ioc->chip->Doorbell));
2148
2149 /*
2150 * Errata workaround for SAS pci express:
2151 * Upon returning to the D0 state, the contents of the doorbell will be
2152 * stale data, and this will incorrectly signal to the host driver that
2153 * the firmware is ready to process mpt commands. The workaround is
2154 * to issue a diagnostic reset.
2155 */
2156 if (ioc->bus_type == SAS && (pdev->device ==
2157 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2158 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2159 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2160 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2161 ioc->name);
2162 goto out;
2163 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302164 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165
2166 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302167 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2168 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2169 CAN_SLEEP);
2170 if (recovery_state != 0)
2171 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2172 "error:[%x]\n", ioc->name, recovery_state);
2173 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302175 "pci-resume: success\n", ioc->name);
2176 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302178
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179}
2180#endif
2181
James Bottomley4ff42a62006-05-17 18:06:52 -05002182static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302183mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002184{
2185 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2186 ioc->bus_type != SPI) ||
2187 (MptDriverClass[index] == MPTFC_DRIVER &&
2188 ioc->bus_type != FC) ||
2189 (MptDriverClass[index] == MPTSAS_DRIVER &&
2190 ioc->bus_type != SAS))
2191 /* make sure we only call the relevant reset handler
2192 * for the bus */
2193 return 0;
2194 return (MptResetHandlers[index])(ioc, reset_phase);
2195}
2196
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002198/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2200 * @ioc: Pointer to MPT adapter structure
2201 * @reason: Event word / reason
2202 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2203 *
2204 * This routine performs all the steps necessary to bring the IOC
2205 * to a OPERATIONAL state.
2206 *
2207 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2208 * MPT adapter.
2209 *
2210 * Returns:
2211 * 0 for success
2212 * -1 if failed to get board READY
2213 * -2 if READY but IOCFacts Failed
2214 * -3 if READY but PrimeIOCFifos Failed
2215 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302216 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302217 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 */
2219static int
2220mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2221{
2222 int hard_reset_done = 0;
2223 int alt_ioc_ready = 0;
2224 int hard;
2225 int rc=0;
2226 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 int ret = 0;
2228 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002229 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302230 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231
Eric Moore29dd3602007-09-14 18:46:51 -06002232 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2233 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
2235 /* Disable reply interrupts (also blocks FreeQ) */
2236 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2237 ioc->active = 0;
2238
2239 if (ioc->alt_ioc) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302240 if (ioc->alt_ioc->active ||
2241 reason == MPT_HOSTEVENT_IOC_RECOVER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 reset_alt_ioc_active = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302243 /* Disable alt-IOC's reply interrupts
2244 * (and FreeQ) for a bit
2245 **/
2246 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2247 0xFFFFFFFF);
2248 ioc->alt_ioc->active = 0;
2249 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 }
2251
2252 hard = 1;
2253 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2254 hard = 0;
2255
2256 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2257 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002258 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2259 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260
2261 if (reset_alt_ioc_active && ioc->alt_ioc) {
2262 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002263 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2264 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002265 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 ioc->alt_ioc->active = 1;
2267 }
2268
2269 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302270 printk(MYIOC_s_WARN_FMT
2271 "NOT READY WARNING!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302273 ret = -1;
2274 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 }
2276
2277 /* hard_reset_done = 0 if a soft reset was performed
2278 * and 1 if a hard reset was performed.
2279 */
2280 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2281 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2282 alt_ioc_ready = 1;
2283 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05302284 printk(MYIOC_s_WARN_FMT
2285 ": alt-ioc Not ready WARNING!\n",
2286 ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 }
2288
2289 for (ii=0; ii<5; ii++) {
2290 /* Get IOC facts! Allow 5 retries */
2291 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2292 break;
2293 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002294
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295
2296 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002297 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2298 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299 ret = -2;
2300 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2301 MptDisplayIocCapabilities(ioc);
2302 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002303
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 if (alt_ioc_ready) {
2305 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302306 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302307 "Initial Alt IocFacts failed rc=%x\n",
2308 ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 /* Retry - alt IOC was initialized once
2310 */
2311 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2312 }
2313 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302314 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002315 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 alt_ioc_ready = 0;
2317 reset_alt_ioc_active = 0;
2318 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2319 MptDisplayIocCapabilities(ioc->alt_ioc);
2320 }
2321 }
2322
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302323 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2324 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2325 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2326 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2327 IORESOURCE_IO);
2328 if (pci_enable_device(ioc->pcidev))
2329 return -5;
2330 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2331 "mpt"))
2332 return -5;
2333 }
2334
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002335 /*
2336 * Device is reset now. It must have de-asserted the interrupt line
2337 * (if it was asserted) and it should be safe to register for the
2338 * interrupt now.
2339 */
2340 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2341 ioc->pci_irq = -1;
2342 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302343 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002344 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002345 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302346 else
2347 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002348 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002349 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002350 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002351 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Kashyap, Desai2f187862009-05-29 16:52:37 +05302352 "interrupt %d!\n",
2353 ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302354 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002355 pci_disable_msi(ioc->pcidev);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302356 ret = -EBUSY;
2357 goto out;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002358 }
2359 irq_allocated = 1;
2360 ioc->pci_irq = ioc->pcidev->irq;
2361 pci_set_master(ioc->pcidev); /* ?? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302362 pci_set_drvdata(ioc->pcidev, ioc);
2363 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2364 "installed at interrupt %d\n", ioc->name,
2365 ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002366 }
2367 }
2368
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 /* Prime reply & request queues!
2370 * (mucho alloc's) Must be done prior to
2371 * init as upper addresses are needed for init.
2372 * If fails, continue with alt-ioc processing
2373 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302374 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
2375 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2377 ret = -3;
2378
2379 /* May need to check/upload firmware & data here!
2380 * If fails, continue with alt-ioc processing
2381 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302382 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
2383 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2385 ret = -4;
2386// NEW!
2387 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302388 printk(MYIOC_s_WARN_FMT
2389 ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002390 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 alt_ioc_ready = 0;
2392 reset_alt_ioc_active = 0;
2393 }
2394
2395 if (alt_ioc_ready) {
2396 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2397 alt_ioc_ready = 0;
2398 reset_alt_ioc_active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302399 printk(MYIOC_s_WARN_FMT
2400 ": alt-ioc: (%d) init failure WARNING!\n",
2401 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 }
2403 }
2404
2405 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2406 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302407 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002408 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409
2410 /* Controller is not operational, cannot do upload
2411 */
2412 if (ret == 0) {
2413 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002414 if (rc == 0) {
2415 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2416 /*
2417 * Maintain only one pointer to FW memory
2418 * so there will not be two attempt to
2419 * downloadboot onboard dual function
2420 * chips (mpt_adapter_disable,
2421 * mpt_diag_reset)
2422 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302423 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002424 "mpt_upload: alt_%s has cached_fw=%p \n",
2425 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302426 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002427 }
2428 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002429 printk(MYIOC_s_WARN_FMT
2430 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302431 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 }
2434 }
2435 }
2436
Kashyap, Desaifd761752009-05-29 16:39:06 +05302437 /* Enable MPT base driver management of EventNotification
2438 * and EventAck handling.
2439 */
2440 if ((ret == 0) && (!ioc->facts.EventState)) {
2441 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2442 "SendEventNotification\n",
2443 ioc->name));
2444 ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
2445 }
2446
2447 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2448 rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
2449
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 if (ret == 0) {
2451 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002452 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 ioc->active = 1;
2454 }
Kashyap, Desaifd761752009-05-29 16:39:06 +05302455 if (rc == 0) { /* alt ioc */
2456 if (reset_alt_ioc_active && ioc->alt_ioc) {
2457 /* (re)Enable alt-IOC! (reply interrupt) */
2458 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
2459 "reply irq re-enabled\n",
2460 ioc->alt_ioc->name));
2461 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2462 MPI_HIM_DIM);
2463 ioc->alt_ioc->active = 1;
2464 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 }
2466
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002468 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2470 * recursive scenario; GetLanConfigPages times out, timer expired
2471 * routine calls HardResetHandler, which calls into here again,
2472 * and we try GetLanConfigPages again...
2473 */
2474 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002475
2476 /*
2477 * Initalize link list for inactive raid volumes.
2478 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002479 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002480 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2481
Kashyap, Desai2f187862009-05-29 16:52:37 +05302482 switch (ioc->bus_type) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002483
Kashyap, Desai2f187862009-05-29 16:52:37 +05302484 case SAS:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002485 /* clear persistency table */
2486 if(ioc->facts.IOCExceptions &
2487 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2488 ret = mptbase_sas_persist_operation(ioc,
2489 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2490 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002491 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002492 }
2493
2494 /* Find IM volumes
2495 */
2496 mpt_findImVolumes(ioc);
2497
Kashyap, Desai2f187862009-05-29 16:52:37 +05302498 /* Check, and possibly reset, the coalescing value
2499 */
2500 mpt_read_ioc_pg_1(ioc);
2501
2502 break;
2503
2504 case FC:
2505 if ((ioc->pfacts[0].ProtocolFlags &
2506 MPI_PORTFACTS_PROTOCOL_LAN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2508 /*
2509 * Pre-fetch the ports LAN MAC address!
2510 * (LANPage1_t stuff)
2511 */
2512 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302513 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2514 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302515 "LanAddr = %02X:%02X:%02X"
2516 ":%02X:%02X:%02X\n",
2517 ioc->name, a[5], a[4],
2518 a[3], a[2], a[1], a[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302520 break;
2521
2522 case SPI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 /* Get NVRAM and adapter maximums from SPP 0 and 2
2524 */
2525 mpt_GetScsiPortSettings(ioc, 0);
2526
2527 /* Get version and length of SDP 1
2528 */
2529 mpt_readScsiDevicePageHeaders(ioc, 0);
2530
2531 /* Find IM volumes
2532 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002533 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 mpt_findImVolumes(ioc);
2535
2536 /* Check, and possibly reset, the coalescing value
2537 */
2538 mpt_read_ioc_pg_1(ioc);
2539
2540 mpt_read_ioc_pg_4(ioc);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302541
2542 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 }
2544
2545 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302546 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 }
2548
Eric Moore0ccdb002006-07-11 17:33:13 -06002549 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002550 if ((ret != 0) && irq_allocated) {
2551 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302552 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002553 pci_disable_msi(ioc->pcidev);
2554 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 return ret;
2556}
2557
2558/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002559/**
2560 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 * @ioc: Pointer to MPT adapter structure
2562 * @pdev: Pointer to (struct pci_dev) structure
2563 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002564 * Search for PCI bus/dev_function which matches
2565 * PCI bus/dev_function (+/-1) for newly discovered 929,
2566 * 929X, 1030 or 1035.
2567 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2569 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2570 */
2571static void
2572mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2573{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002574 struct pci_dev *peer=NULL;
2575 unsigned int slot = PCI_SLOT(pdev->devfn);
2576 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 MPT_ADAPTER *ioc_srch;
2578
Prakash, Sathya436ace72007-07-24 15:42:08 +05302579 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002580 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002581 ioc->name, pci_name(pdev), pdev->bus->number,
2582 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002583
2584 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2585 if (!peer) {
2586 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2587 if (!peer)
2588 return;
2589 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590
2591 list_for_each_entry(ioc_srch, &ioc_list, list) {
2592 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002593 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 /* Paranoia checks */
2595 if (ioc->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302596 printk(MYIOC_s_WARN_FMT
2597 "Oops, already bound (%s <==> %s)!\n",
2598 ioc->name, ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 break;
2600 } else if (ioc_srch->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302601 printk(MYIOC_s_WARN_FMT
2602 "Oops, already bound (%s <==> %s)!\n",
2603 ioc_srch->name, ioc_srch->name,
2604 ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 break;
2606 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302607 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2608 "FOUND! binding %s <==> %s\n",
2609 ioc->name, ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 ioc_srch->alt_ioc = ioc;
2611 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 }
2613 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002614 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615}
2616
2617/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002618/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002620 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 */
2622static void
2623mpt_adapter_disable(MPT_ADAPTER *ioc)
2624{
2625 int sz;
2626 int ret;
2627
2628 if (ioc->cached_fw != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302629 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2630 "%s: Pushing FW onto adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302631 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2632 ioc->cached_fw, CAN_SLEEP)) < 0) {
2633 printk(MYIOC_s_WARN_FMT
2634 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002635 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 }
2637 }
2638
Kashyap, Desai71278192009-05-29 16:53:14 +05302639 /*
2640 * Put the controller into ready state (if its not already)
2641 */
2642 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {
2643 if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
2644 CAN_SLEEP)) {
2645 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)
2646 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit "
2647 "reset failed to put ioc in ready state!\n",
2648 ioc->name, __func__);
2649 } else
2650 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset "
2651 "failed!\n", ioc->name, __func__);
2652 }
2653
2654
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 /* Disable adapter interrupts! */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302656 synchronize_irq(ioc->pcidev->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2658 ioc->active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302659
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 /* Clear any lingering interrupt */
2661 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302662 CHIPREG_READ32(&ioc->chip->IntStatus);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663
2664 if (ioc->alloc != NULL) {
2665 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002666 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2667 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 pci_free_consistent(ioc->pcidev, sz,
2669 ioc->alloc, ioc->alloc_dma);
2670 ioc->reply_frames = NULL;
2671 ioc->req_frames = NULL;
2672 ioc->alloc = NULL;
2673 ioc->alloc_total -= sz;
2674 }
2675
2676 if (ioc->sense_buf_pool != NULL) {
2677 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2678 pci_free_consistent(ioc->pcidev, sz,
2679 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2680 ioc->sense_buf_pool = NULL;
2681 ioc->alloc_total -= sz;
2682 }
2683
2684 if (ioc->events != NULL){
2685 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2686 kfree(ioc->events);
2687 ioc->events = NULL;
2688 ioc->alloc_total -= sz;
2689 }
2690
Prakash, Sathya984621b2008-01-11 14:42:17 +05302691 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002693 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002694 mpt_inactive_raid_list_free(ioc);
2695 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002696 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002697 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002698 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699
2700 if (ioc->spi_data.pIocPg4 != NULL) {
2701 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302702 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 ioc->spi_data.pIocPg4,
2704 ioc->spi_data.IocPg4_dma);
2705 ioc->spi_data.pIocPg4 = NULL;
2706 ioc->alloc_total -= sz;
2707 }
2708
2709 if (ioc->ReqToChain != NULL) {
2710 kfree(ioc->ReqToChain);
2711 kfree(ioc->RequestNB);
2712 ioc->ReqToChain = NULL;
2713 }
2714
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002715 kfree(ioc->ChainToChain);
2716 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002717
2718 if (ioc->HostPageBuffer != NULL) {
2719 if((ret = mpt_host_page_access_control(ioc,
2720 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002721 printk(MYIOC_s_ERR_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302722 ": %s: host page buffers free failed (%d)!\n",
2723 ioc->name, __func__, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002724 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302725 dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2726 "HostPageBuffer free @ %p, sz=%d bytes\n",
2727 ioc->name, ioc->HostPageBuffer,
2728 ioc->HostPageBuffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002729 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002730 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002731 ioc->HostPageBuffer = NULL;
2732 ioc->HostPageBuffer_sz = 0;
2733 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2734 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735
Kashyap, Desai2f187862009-05-29 16:52:37 +05302736 pci_set_drvdata(ioc->pcidev, NULL);
2737}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002739/**
2740 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 * @ioc: Pointer to MPT adapter structure
2742 *
2743 * This routine unregisters h/w resources and frees all alloc'd memory
2744 * associated with a MPT adapter structure.
2745 */
2746static void
2747mpt_adapter_dispose(MPT_ADAPTER *ioc)
2748{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002749 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002751 if (ioc == NULL)
2752 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002754 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002756 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002758 if (ioc->pci_irq != -1) {
2759 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302760 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002761 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002762 ioc->pci_irq = -1;
2763 }
2764
2765 if (ioc->memmap != NULL) {
2766 iounmap(ioc->memmap);
2767 ioc->memmap = NULL;
2768 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302770 pci_disable_device(ioc->pcidev);
2771 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2772
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002774 if (ioc->mtrr_reg > 0) {
2775 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002776 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002777 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778#endif
2779
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002780 /* Zap the adapter lookup ptr! */
2781 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002783 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002784 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2785 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002786
2787 if (ioc->alt_ioc)
2788 ioc->alt_ioc->alt_ioc = NULL;
2789
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002790 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791}
2792
2793/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002794/**
2795 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 * @ioc: Pointer to MPT adapter structure
2797 */
2798static void
2799MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2800{
2801 int i = 0;
2802
2803 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302804 if (ioc->prod_name)
2805 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 printk("Capabilities={");
2807
2808 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2809 printk("Initiator");
2810 i++;
2811 }
2812
2813 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2814 printk("%sTarget", i ? "," : "");
2815 i++;
2816 }
2817
2818 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2819 printk("%sLAN", i ? "," : "");
2820 i++;
2821 }
2822
2823#if 0
2824 /*
2825 * This would probably evoke more questions than it's worth
2826 */
2827 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2828 printk("%sLogBusAddr", i ? "," : "");
2829 i++;
2830 }
2831#endif
2832
2833 printk("}\n");
2834}
2835
2836/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002837/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2839 * @ioc: Pointer to MPT_ADAPTER structure
2840 * @force: Force hard KickStart of IOC
2841 * @sleepFlag: Specifies whether the process can sleep
2842 *
2843 * Returns:
2844 * 1 - DIAG reset and READY
2845 * 0 - READY initially OR soft reset and READY
2846 * -1 - Any failure on KickStart
2847 * -2 - Msg Unit Reset Failed
2848 * -3 - IO Unit Reset Failed
2849 * -4 - IOC owned by a PEER
2850 */
2851static int
2852MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2853{
2854 u32 ioc_state;
2855 int statefault = 0;
2856 int cntdn;
2857 int hard_reset_done = 0;
2858 int r;
2859 int ii;
2860 int whoinit;
2861
2862 /* Get current [raw] IOC state */
2863 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002864 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865
2866 /*
2867 * Check to see if IOC got left/stuck in doorbell handshake
2868 * grip of death. If so, hard reset the IOC.
2869 */
2870 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2871 statefault = 1;
2872 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2873 ioc->name);
2874 }
2875
2876 /* Is it already READY? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302877 if (!statefault &&
2878 ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) {
2879 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2880 "IOC is in READY state\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 return 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302882 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883
2884 /*
2885 * Check to see if IOC is in FAULT state.
2886 */
2887 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2888 statefault = 2;
2889 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002890 ioc->name);
2891 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2892 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 }
2894
2895 /*
2896 * Hmmm... Did it get left operational?
2897 */
2898 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302899 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900 ioc->name));
2901
2902 /* Check WhoInit.
2903 * If PCI Peer, exit.
2904 * Else, if no fault conditions are present, issue a MessageUnitReset
2905 * Else, fall through to KickStart case
2906 */
2907 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002908 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2909 "whoinit 0x%x statefault %d force %d\n",
2910 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 if (whoinit == MPI_WHOINIT_PCI_PEER)
2912 return -4;
2913 else {
2914 if ((statefault == 0 ) && (force == 0)) {
2915 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2916 return 0;
2917 }
2918 statefault = 3;
2919 }
2920 }
2921
2922 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2923 if (hard_reset_done < 0)
2924 return -1;
2925
2926 /*
2927 * Loop here waiting for IOC to come READY.
2928 */
2929 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002930 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931
2932 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2933 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2934 /*
2935 * BIOS or previous driver load left IOC in OP state.
2936 * Reset messaging FIFOs.
2937 */
2938 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2939 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2940 return -2;
2941 }
2942 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2943 /*
2944 * Something is wrong. Try to get IOC back
2945 * to a known state.
2946 */
2947 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2948 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2949 return -3;
2950 }
2951 }
2952
2953 ii++; cntdn--;
2954 if (!cntdn) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302955 printk(MYIOC_s_ERR_FMT
2956 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
2957 ioc->name, ioc_state, (int)((ii+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 return -ETIME;
2959 }
2960
2961 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002962 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 } else {
2964 mdelay (1); /* 1 msec delay */
2965 }
2966
2967 }
2968
2969 if (statefault < 3) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302970 printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name,
2971 statefault == 1 ? "stuck handshake" : "IOC FAULT");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 }
2973
2974 return hard_reset_done;
2975}
2976
2977/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002978/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 * mpt_GetIocState - Get the current state of a MPT adapter.
2980 * @ioc: Pointer to MPT_ADAPTER structure
2981 * @cooked: Request raw or cooked IOC state
2982 *
2983 * Returns all IOC Doorbell register bits if cooked==0, else just the
2984 * Doorbell bits in MPI_IOC_STATE_MASK.
2985 */
2986u32
2987mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2988{
2989 u32 s, sc;
2990
2991 /* Get! */
2992 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 sc = s & MPI_IOC_STATE_MASK;
2994
2995 /* Save! */
2996 ioc->last_state = sc;
2997
2998 return cooked ? sc : s;
2999}
3000
3001/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003002/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 * GetIocFacts - Send IOCFacts request to MPT adapter.
3004 * @ioc: Pointer to MPT_ADAPTER structure
3005 * @sleepFlag: Specifies whether the process can sleep
3006 * @reason: If recovery, only update facts.
3007 *
3008 * Returns 0 for success, non-zero for failure.
3009 */
3010static int
3011GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
3012{
3013 IOCFacts_t get_facts;
3014 IOCFactsReply_t *facts;
3015 int r;
3016 int req_sz;
3017 int reply_sz;
3018 int sz;
3019 u32 status, vv;
3020 u8 shiftFactor=1;
3021
3022 /* IOC *must* NOT be in RESET state! */
3023 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303024 printk(KERN_ERR MYNAM
3025 ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
3026 ioc->name, ioc->last_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 return -44;
3028 }
3029
3030 facts = &ioc->facts;
3031
3032 /* Destination (reply area)... */
3033 reply_sz = sizeof(*facts);
3034 memset(facts, 0, reply_sz);
3035
3036 /* Request area (get_facts on the stack right now!) */
3037 req_sz = sizeof(get_facts);
3038 memset(&get_facts, 0, req_sz);
3039
3040 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
3041 /* Assert: All other get_facts fields are zero! */
3042
Prakash, Sathya436ace72007-07-24 15:42:08 +05303043 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003044 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 ioc->name, req_sz, reply_sz));
3046
3047 /* No non-zero fields in the get_facts request are greater than
3048 * 1 byte in size, so we can just fire it off as is.
3049 */
3050 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3051 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3052 if (r != 0)
3053 return r;
3054
3055 /*
3056 * Now byte swap (GRRR) the necessary fields before any further
3057 * inspection of reply contents.
3058 *
3059 * But need to do some sanity checks on MsgLength (byte) field
3060 * to make sure we don't zero IOC's req_sz!
3061 */
3062 /* Did we get a valid reply? */
3063 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3064 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3065 /*
3066 * If not been here, done that, save off first WhoInit value
3067 */
3068 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3069 ioc->FirstWhoInit = facts->WhoInit;
3070 }
3071
3072 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3073 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3074 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3075 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3076 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003077 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 /* CHECKME! IOCStatus, IOCLogInfo */
3079
3080 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3081 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3082
3083 /*
3084 * FC f/w version changed between 1.1 and 1.2
3085 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3086 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3087 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303088 if (facts->MsgVersion < MPI_VERSION_01_02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 /*
3090 * Handle old FC f/w style, convert to new...
3091 */
3092 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3093 facts->FWVersion.Word =
3094 ((oldv<<12) & 0xFF000000) |
3095 ((oldv<<8) & 0x000FFF00);
3096 } else
3097 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3098
3099 facts->ProductID = le16_to_cpu(facts->ProductID);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303100
Eric Mooreb506ade2007-01-29 09:45:37 -07003101 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3102 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3103 ioc->ir_firmware = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303104
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 facts->CurrentHostMfaHighAddr =
3106 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3107 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3108 facts->CurrentSenseBufferHighAddr =
3109 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3110 facts->CurReplyFrameSize =
3111 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003112 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113
3114 /*
3115 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3116 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3117 * to 14 in MPI-1.01.0x.
3118 */
3119 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
Kashyap, Desai2f187862009-05-29 16:52:37 +05303120 facts->MsgVersion > MPI_VERSION_01_00) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3122 }
3123
3124 sz = facts->FWImageSize;
3125 if ( sz & 0x01 )
3126 sz += 1;
3127 if ( sz & 0x02 )
3128 sz += 2;
3129 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003130
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 if (!facts->RequestFrameSize) {
3132 /* Something is wrong! */
3133 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3134 ioc->name);
3135 return -55;
3136 }
3137
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003138 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 vv = ((63 / (sz * 4)) + 1) & 0x03;
3140 ioc->NB_for_64_byte_frame = vv;
3141 while ( sz )
3142 {
3143 shiftFactor++;
3144 sz = sz >> 1;
3145 }
3146 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303147 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003148 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3149 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003150
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3152 /*
3153 * Set values for this IOC's request & reply frame sizes,
3154 * and request & reply queue depths...
3155 */
3156 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3157 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3158 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3159 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3160
Prakash, Sathya436ace72007-07-24 15:42:08 +05303161 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303163 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 ioc->name, ioc->req_sz, ioc->req_depth));
3165
3166 /* Get port facts! */
3167 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3168 return r;
3169 }
3170 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003171 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3173 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3174 RequestFrameSize)/sizeof(u32)));
3175 return -66;
3176 }
3177
3178 return 0;
3179}
3180
3181/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003182/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183 * GetPortFacts - Send PortFacts request to MPT adapter.
3184 * @ioc: Pointer to MPT_ADAPTER structure
3185 * @portnum: Port number
3186 * @sleepFlag: Specifies whether the process can sleep
3187 *
3188 * Returns 0 for success, non-zero for failure.
3189 */
3190static int
3191GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3192{
3193 PortFacts_t get_pfacts;
3194 PortFactsReply_t *pfacts;
3195 int ii;
3196 int req_sz;
3197 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003198 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199
3200 /* IOC *must* NOT be in RESET state! */
3201 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003202 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3203 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204 return -4;
3205 }
3206
3207 pfacts = &ioc->pfacts[portnum];
3208
3209 /* Destination (reply area)... */
3210 reply_sz = sizeof(*pfacts);
3211 memset(pfacts, 0, reply_sz);
3212
3213 /* Request area (get_pfacts on the stack right now!) */
3214 req_sz = sizeof(get_pfacts);
3215 memset(&get_pfacts, 0, req_sz);
3216
3217 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3218 get_pfacts.PortNumber = portnum;
3219 /* Assert: All other get_pfacts fields are zero! */
3220
Prakash, Sathya436ace72007-07-24 15:42:08 +05303221 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 ioc->name, portnum));
3223
3224 /* No non-zero fields in the get_pfacts request are greater than
3225 * 1 byte in size, so we can just fire it off as is.
3226 */
3227 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3228 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3229 if (ii != 0)
3230 return ii;
3231
3232 /* Did we get a valid reply? */
3233
3234 /* Now byte swap the necessary fields in the response. */
3235 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3236 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3237 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3238 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3239 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3240 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3241 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3242 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3243 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3244
Eric Moore793955f2007-01-29 09:42:20 -07003245 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3246 pfacts->MaxDevices;
3247 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3248 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3249
3250 /*
3251 * Place all the devices on channels
3252 *
3253 * (for debuging)
3254 */
3255 if (mpt_channel_mapping) {
3256 ioc->devices_per_bus = 1;
3257 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3258 }
3259
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 return 0;
3261}
3262
3263/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003264/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265 * SendIocInit - Send IOCInit request to MPT adapter.
3266 * @ioc: Pointer to MPT_ADAPTER structure
3267 * @sleepFlag: Specifies whether the process can sleep
3268 *
3269 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3270 *
3271 * Returns 0 for success, non-zero for failure.
3272 */
3273static int
3274SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3275{
3276 IOCInit_t ioc_init;
3277 MPIDefaultReply_t init_reply;
3278 u32 state;
3279 int r;
3280 int count;
3281 int cntdn;
3282
3283 memset(&ioc_init, 0, sizeof(ioc_init));
3284 memset(&init_reply, 0, sizeof(init_reply));
3285
3286 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3287 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3288
3289 /* If we are in a recovery mode and we uploaded the FW image,
3290 * then this pointer is not NULL. Skip the upload a second time.
3291 * Set this flag if cached_fw set for either IOC.
3292 */
3293 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3294 ioc->upload_fw = 1;
3295 else
3296 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303297 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3299
Eric Moore793955f2007-01-29 09:42:20 -07003300 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3301 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303302
Prakash, Sathya436ace72007-07-24 15:42:08 +05303303 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003304 ioc->name, ioc->facts.MsgVersion));
3305 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3306 // set MsgVersion and HeaderVersion host driver was built with
3307 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3308 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003310 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3311 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3312 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3313 return -99;
3314 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3316
Kashyap, Desai2f187862009-05-29 16:52:37 +05303317 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 /* Save the upper 32-bits of the request
3319 * (reply) and sense buffers.
3320 */
3321 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3322 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3323 } else {
3324 /* Force 32-bit addressing */
3325 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3326 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3327 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003328
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3330 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003331 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3332 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333
Prakash, Sathya436ace72007-07-24 15:42:08 +05303334 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335 ioc->name, &ioc_init));
3336
3337 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3338 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003339 if (r != 0) {
3340 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003342 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343
3344 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003345 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 */
3347
Prakash, Sathya436ace72007-07-24 15:42:08 +05303348 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003350
3351 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3352 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003354 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355
3356 /* YIKES! SUPER IMPORTANT!!!
3357 * Poll IocState until _OPERATIONAL while IOC is doing
3358 * LoopInit and TargetDiscovery!
3359 */
3360 count = 0;
3361 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3362 state = mpt_GetIocState(ioc, 1);
3363 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3364 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003365 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 } else {
3367 mdelay(1);
3368 }
3369
3370 if (!cntdn) {
3371 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3372 ioc->name, (int)((count+5)/HZ));
3373 return -9;
3374 }
3375
3376 state = mpt_GetIocState(ioc, 1);
3377 count++;
3378 }
Eric Moore29dd3602007-09-14 18:46:51 -06003379 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 ioc->name, count));
3381
Eric Mooreba856d32006-07-11 17:34:01 -06003382 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 return r;
3384}
3385
3386/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003387/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 * SendPortEnable - Send PortEnable request to MPT adapter port.
3389 * @ioc: Pointer to MPT_ADAPTER structure
3390 * @portnum: Port number to enable
3391 * @sleepFlag: Specifies whether the process can sleep
3392 *
3393 * Send PortEnable to bring IOC to OPERATIONAL state.
3394 *
3395 * Returns 0 for success, non-zero for failure.
3396 */
3397static int
3398SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3399{
3400 PortEnable_t port_enable;
3401 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003402 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 int req_sz;
3404 int reply_sz;
3405
3406 /* Destination... */
3407 reply_sz = sizeof(MPIDefaultReply_t);
3408 memset(&reply_buf, 0, reply_sz);
3409
3410 req_sz = sizeof(PortEnable_t);
3411 memset(&port_enable, 0, req_sz);
3412
3413 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3414 port_enable.PortNumber = portnum;
3415/* port_enable.ChainOffset = 0; */
3416/* port_enable.MsgFlags = 0; */
3417/* port_enable.MsgContext = 0; */
3418
Prakash, Sathya436ace72007-07-24 15:42:08 +05303419 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 ioc->name, portnum, &port_enable));
3421
3422 /* RAID FW may take a long time to enable
3423 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003424 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003425 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3426 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3427 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003428 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003429 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3430 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3431 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003433 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434}
3435
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003436/**
3437 * mpt_alloc_fw_memory - allocate firmware memory
3438 * @ioc: Pointer to MPT_ADAPTER structure
3439 * @size: total FW bytes
3440 *
3441 * If memory has already been allocated, the same (cached) value
3442 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303443 *
3444 * Return 0 if successfull, or non-zero for failure
3445 **/
3446int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3448{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303449 int rc;
3450
3451 if (ioc->cached_fw) {
3452 rc = 0; /* use already allocated memory */
3453 goto out;
3454 }
3455 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3457 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303458 rc = 0;
3459 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303461 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3462 if (!ioc->cached_fw) {
3463 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3464 ioc->name);
3465 rc = -1;
3466 } else {
3467 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3468 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3469 ioc->alloc_total += size;
3470 rc = 0;
3471 }
3472 out:
3473 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303475
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003476/**
3477 * mpt_free_fw_memory - free firmware memory
3478 * @ioc: Pointer to MPT_ADAPTER structure
3479 *
3480 * If alt_img is NULL, delete from ioc structure.
3481 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303482 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483void
3484mpt_free_fw_memory(MPT_ADAPTER *ioc)
3485{
3486 int sz;
3487
Prakash, Sathya984621b2008-01-11 14:42:17 +05303488 if (!ioc->cached_fw)
3489 return;
3490
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303492 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3493 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003494 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303495 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497}
3498
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003500/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3502 * @ioc: Pointer to MPT_ADAPTER structure
3503 * @sleepFlag: Specifies whether the process can sleep
3504 *
3505 * Returns 0 for success, >0 for handshake failure
3506 * <0 for fw upload failure.
3507 *
3508 * Remark: If bound IOC and a successful FWUpload was performed
3509 * on the bound IOC, the second image is discarded
3510 * and memory is free'd. Both channels must upload to prevent
3511 * IOC from running in degraded mode.
3512 */
3513static int
3514mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3515{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 u8 reply[sizeof(FWUploadReply_t)];
3517 FWUpload_t *prequest;
3518 FWUploadReply_t *preply;
3519 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 u32 flagsLength;
3521 int ii, sz, reply_sz;
3522 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303523 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 /* If the image size is 0, we are done.
3525 */
3526 if ((sz = ioc->facts.FWImageSize) == 0)
3527 return 0;
3528
Prakash, Sathya984621b2008-01-11 14:42:17 +05303529 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3530 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531
Eric Moore29dd3602007-09-14 18:46:51 -06003532 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3533 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003534
Eric Moorebc6e0892007-09-29 10:16:28 -06003535 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3536 kzalloc(ioc->req_sz, GFP_KERNEL);
3537 if (!prequest) {
3538 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3539 "while allocating memory \n", ioc->name));
3540 mpt_free_fw_memory(ioc);
3541 return -ENOMEM;
3542 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543
Eric Moorebc6e0892007-09-29 10:16:28 -06003544 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545
3546 reply_sz = sizeof(reply);
3547 memset(preply, 0, reply_sz);
3548
3549 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3550 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3551
3552 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3553 ptcsge->DetailsLength = 12;
3554 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3555 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003556 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303559 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3560 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3561 ioc->SGE_size;
3562 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3563 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3564 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003565 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303567 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3568 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569
Kashyap, Desai2f187862009-05-29 16:52:37 +05303570 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
3571 "rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572
3573 cmdStatus = -EFAULT;
3574 if (ii == 0) {
3575 /* Handshake transfer was complete and successful.
3576 * Check the Reply Frame.
3577 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303578 int status;
3579 status = le16_to_cpu(preply->IOCStatus) &
3580 MPI_IOCSTATUS_MASK;
3581 if (status == MPI_IOCSTATUS_SUCCESS &&
3582 ioc->facts.FWImageSize ==
3583 le32_to_cpu(preply->ActualImageSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 cmdStatus = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303586 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587 ioc->name, cmdStatus));
3588
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003589
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 if (cmdStatus) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303591 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
3592 "freeing image \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 mpt_free_fw_memory(ioc);
3594 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003595 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596
3597 return cmdStatus;
3598}
3599
3600/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003601/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 * mpt_downloadboot - DownloadBoot code
3603 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003604 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 * @sleepFlag: Specifies whether the process can sleep
3606 *
3607 * FwDownloadBoot requires Programmed IO access.
3608 *
3609 * Returns 0 for success
3610 * -1 FW Image size is 0
3611 * -2 No valid cached_fw Pointer
3612 * <0 for fw upload failure.
3613 */
3614static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003615mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 MpiExtImageHeader_t *pExtImage;
3618 u32 fwSize;
3619 u32 diag0val;
3620 int count;
3621 u32 *ptrFw;
3622 u32 diagRwData;
3623 u32 nextImage;
3624 u32 load_addr;
3625 u32 ioc_state=0;
3626
Prakash, Sathya436ace72007-07-24 15:42:08 +05303627 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003628 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003629
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3631 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3632 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3633 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3634 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3635 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3636
3637 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3638
3639 /* wait 1 msec */
3640 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003641 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 } else {
3643 mdelay (1);
3644 }
3645
3646 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3647 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3648
3649 for (count = 0; count < 30; count ++) {
3650 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3651 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303652 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 ioc->name, count));
3654 break;
3655 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003656 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003658 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003660 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 }
3662 }
3663
3664 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303665 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003666 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667 ioc->name, diag0val));
3668 return -3;
3669 }
3670
3671 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3672 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3673 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3674 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3675 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3676 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3677
3678 /* Set the DiagRwEn and Disable ARM bits */
3679 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3680
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 fwSize = (pFwHeader->ImageSize + 3)/4;
3682 ptrFw = (u32 *) pFwHeader;
3683
3684 /* Write the LoadStartAddress to the DiagRw Address Register
3685 * using Programmed IO
3686 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003687 if (ioc->errata_flag_1064)
3688 pci_enable_io_access(ioc->pcidev);
3689
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303691 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 ioc->name, pFwHeader->LoadStartAddress));
3693
Prakash, Sathya436ace72007-07-24 15:42:08 +05303694 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 ioc->name, fwSize*4, ptrFw));
3696 while (fwSize--) {
3697 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3698 }
3699
3700 nextImage = pFwHeader->NextImageHeaderOffset;
3701 while (nextImage) {
3702 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3703
3704 load_addr = pExtImage->LoadStartAddress;
3705
3706 fwSize = (pExtImage->ImageSize + 3) >> 2;
3707 ptrFw = (u32 *)pExtImage;
3708
Prakash, Sathya436ace72007-07-24 15:42:08 +05303709 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 +02003710 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3712
3713 while (fwSize--) {
3714 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3715 }
3716 nextImage = pExtImage->NextImageHeaderOffset;
3717 }
3718
3719 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303720 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3722
3723 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303724 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3726
3727 /* Clear the internal flash bad bit - autoincrementing register,
3728 * so must do two writes.
3729 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003730 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003731 /*
3732 * 1030 and 1035 H/W errata, workaround to access
3733 * the ClearFlashBadSignatureBit
3734 */
3735 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3736 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3737 diagRwData |= 0x40000000;
3738 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3739 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3740
3741 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3742 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3743 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3744 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3745
3746 /* wait 1 msec */
3747 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003748 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003749 } else {
3750 mdelay (1);
3751 }
3752 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003754 if (ioc->errata_flag_1064)
3755 pci_disable_io_access(ioc->pcidev);
3756
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303758 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003759 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003761 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303762 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763 ioc->name, diag0val));
3764 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3765
3766 /* Write 0xFF to reset the sequencer */
3767 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3768
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003769 if (ioc->bus_type == SAS) {
3770 ioc_state = mpt_GetIocState(ioc, 0);
3771 if ( (GetIocFacts(ioc, sleepFlag,
3772 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303773 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003774 ioc->name, ioc_state));
3775 return -EFAULT;
3776 }
3777 }
3778
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779 for (count=0; count<HZ*20; count++) {
3780 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303781 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3782 "downloadboot successful! (count=%d) IocState=%x\n",
3783 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003784 if (ioc->bus_type == SAS) {
3785 return 0;
3786 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303788 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3789 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 ioc->name));
3791 return -EFAULT;
3792 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303793 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3794 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795 ioc->name));
3796 return 0;
3797 }
3798 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003799 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 } else {
3801 mdelay (10);
3802 }
3803 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303804 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3805 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 return -EFAULT;
3807}
3808
3809/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003810/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811 * KickStart - Perform hard reset of MPT adapter.
3812 * @ioc: Pointer to MPT_ADAPTER structure
3813 * @force: Force hard reset
3814 * @sleepFlag: Specifies whether the process can sleep
3815 *
3816 * This routine places MPT adapter in diagnostic mode via the
3817 * WriteSequence register, and then performs a hard reset of adapter
3818 * via the Diagnostic register.
3819 *
3820 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3821 * or NO_SLEEP (interrupt thread, use mdelay)
3822 * force - 1 if doorbell active, board fault state
3823 * board operational, IOC_RECOVERY or
3824 * IOC_BRINGUP and there is an alt_ioc.
3825 * 0 else
3826 *
3827 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003828 * 1 - hard reset, READY
3829 * 0 - no reset due to History bit, READY
3830 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 * OR reset but failed to come READY
3832 * -2 - no reset, could not enter DIAG mode
3833 * -3 - reset but bad FW bit
3834 */
3835static int
3836KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3837{
3838 int hard_reset_done = 0;
3839 u32 ioc_state=0;
3840 int cnt,cntdn;
3841
Eric Moore29dd3602007-09-14 18:46:51 -06003842 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003843 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844 /* Always issue a Msg Unit Reset first. This will clear some
3845 * SCSI bus hang conditions.
3846 */
3847 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3848
3849 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003850 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003851 } else {
3852 mdelay (1000);
3853 }
3854 }
3855
3856 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3857 if (hard_reset_done < 0)
3858 return hard_reset_done;
3859
Prakash, Sathya436ace72007-07-24 15:42:08 +05303860 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003861 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862
3863 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3864 for (cnt=0; cnt<cntdn; cnt++) {
3865 ioc_state = mpt_GetIocState(ioc, 1);
3866 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303867 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868 ioc->name, cnt));
3869 return hard_reset_done;
3870 }
3871 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003872 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 } else {
3874 mdelay (10);
3875 }
3876 }
3877
Eric Moore29dd3602007-09-14 18:46:51 -06003878 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3879 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880 return -1;
3881}
3882
3883/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003884/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885 * mpt_diag_reset - Perform hard reset of the adapter.
3886 * @ioc: Pointer to MPT_ADAPTER structure
3887 * @ignore: Set if to honor and clear to ignore
3888 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003889 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 * else set to NO_SLEEP (use mdelay instead)
3891 *
3892 * This routine places the adapter in diagnostic mode via the
3893 * WriteSequence register and then performs a hard reset of adapter
3894 * via the Diagnostic register. Adapter should be in ready state
3895 * upon successful completion.
3896 *
3897 * Returns: 1 hard reset successful
3898 * 0 no reset performed because reset history bit set
3899 * -2 enabling diagnostic mode failed
3900 * -3 diagnostic reset failed
3901 */
3902static int
3903mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3904{
3905 u32 diag0val;
3906 u32 doorbell;
3907 int hard_reset_done = 0;
3908 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303910 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Kashyap, Desaid1306912009-08-05 12:53:51 +05303911 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912
Eric Moorecd2c6192007-01-29 09:47:47 -07003913 /* Clear any existing interrupts */
3914 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3915
Eric Moore87cf8982006-06-27 16:09:26 -06003916 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303917
3918 if (!ignore)
3919 return 0;
3920
Prakash, Sathya436ace72007-07-24 15:42:08 +05303921 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003922 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003923 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3924 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3925 if (sleepFlag == CAN_SLEEP)
3926 msleep(1);
3927 else
3928 mdelay(1);
3929
Kashyap, Desaid1306912009-08-05 12:53:51 +05303930 /*
3931 * Call each currently registered protocol IOC reset handler
3932 * with pre-reset indication.
3933 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3934 * MptResetHandlers[] registered yet.
3935 */
3936 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3937 if (MptResetHandlers[cb_idx])
3938 (*(MptResetHandlers[cb_idx]))(ioc,
3939 MPT_IOC_PRE_RESET);
3940 }
3941
Eric Moore87cf8982006-06-27 16:09:26 -06003942 for (count = 0; count < 60; count ++) {
3943 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3944 doorbell &= MPI_IOC_STATE_MASK;
3945
Prakash, Sathya436ace72007-07-24 15:42:08 +05303946 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003947 "looking for READY STATE: doorbell=%x"
3948 " count=%d\n",
3949 ioc->name, doorbell, count));
Kashyap, Desai2f187862009-05-29 16:52:37 +05303950
Eric Moore87cf8982006-06-27 16:09:26 -06003951 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003952 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003953 }
3954
3955 /* wait 1 sec */
3956 if (sleepFlag == CAN_SLEEP)
3957 msleep(1000);
3958 else
3959 mdelay(1000);
3960 }
3961 return -1;
3962 }
3963
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 /* Use "Diagnostic reset" method! (only thing available!) */
3965 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3966
Prakash, Sathya436ace72007-07-24 15:42:08 +05303967 if (ioc->debug_level & MPT_DEBUG) {
3968 if (ioc->alt_ioc)
3969 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3970 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303972 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973
3974 /* Do the reset if we are told to ignore the reset history
3975 * or if the reset history is 0
3976 */
3977 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3978 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3979 /* Write magic sequence to WriteSequence register
3980 * Loop until in diagnostic mode
3981 */
3982 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3983 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3984 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3985 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3986 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3987 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3988
3989 /* wait 100 msec */
3990 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003991 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 } else {
3993 mdelay (100);
3994 }
3995
3996 count++;
3997 if (count > 20) {
3998 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3999 ioc->name, diag0val);
4000 return -2;
4001
4002 }
4003
4004 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4005
Prakash, Sathya436ace72007-07-24 15:42:08 +05304006 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 ioc->name, diag0val));
4008 }
4009
Prakash, Sathya436ace72007-07-24 15:42:08 +05304010 if (ioc->debug_level & MPT_DEBUG) {
4011 if (ioc->alt_ioc)
4012 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4013 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304015 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 /*
4017 * Disable the ARM (Bug fix)
4018 *
4019 */
4020 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004021 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022
4023 /*
4024 * Now hit the reset bit in the Diagnostic register
4025 * (THE BIG HAMMER!) (Clears DRWE bit).
4026 */
4027 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
4028 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304029 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030 ioc->name));
4031
4032 /*
4033 * Call each currently registered protocol IOC reset handler
4034 * with pre-reset indication.
4035 * NOTE: If we're doing _IOC_BRINGUP, there can be no
4036 * MptResetHandlers[] registered yet.
4037 */
Kashyap, Desaid1306912009-08-05 12:53:51 +05304038 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
4039 if (MptResetHandlers[cb_idx]) {
4040 mpt_signal_reset(cb_idx,
4041 ioc, MPT_IOC_PRE_RESET);
4042 if (ioc->alt_ioc) {
4043 mpt_signal_reset(cb_idx,
4044 ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 }
4046 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047 }
4048
Eric Moore0ccdb002006-07-11 17:33:13 -06004049 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304050 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06004051 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304052 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4053 else
4054 cached_fw = NULL;
4055 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056 /* If the DownloadBoot operation fails, the
4057 * IOC will be left unusable. This is a fatal error
4058 * case. _diag_reset will return < 0
4059 */
4060 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304061 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4063 break;
4064 }
4065
Prakash, Sathya436ace72007-07-24 15:42:08 +05304066 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304067 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 /* wait 1 sec */
4069 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004070 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071 } else {
4072 mdelay (1000);
4073 }
4074 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304075 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004076 printk(MYIOC_s_WARN_FMT
4077 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078 }
4079
4080 } else {
4081 /* Wait for FW to reload and for board
4082 * to go to the READY state.
4083 * Maximum wait is 60 seconds.
4084 * If fail, no error will check again
4085 * with calling program.
4086 */
4087 for (count = 0; count < 60; count ++) {
4088 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4089 doorbell &= MPI_IOC_STATE_MASK;
4090
Kashyap, Desai2f187862009-05-29 16:52:37 +05304091 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4092 "looking for READY STATE: doorbell=%x"
4093 " count=%d\n", ioc->name, doorbell, count));
4094
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095 if (doorbell == MPI_IOC_STATE_READY) {
4096 break;
4097 }
4098
4099 /* wait 1 sec */
4100 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004101 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102 } else {
4103 mdelay (1000);
4104 }
4105 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05304106
4107 if (doorbell != MPI_IOC_STATE_READY)
4108 printk(MYIOC_s_ERR_FMT "Failed to come READY "
4109 "after reset! IocState=%x", ioc->name,
4110 doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111 }
4112 }
4113
4114 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304115 if (ioc->debug_level & MPT_DEBUG) {
4116 if (ioc->alt_ioc)
4117 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4118 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4119 ioc->name, diag0val, diag1val));
4120 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121
4122 /* Clear RESET_HISTORY bit! Place board in the
4123 * diagnostic mode to update the diag register.
4124 */
4125 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4126 count = 0;
4127 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4128 /* Write magic sequence to WriteSequence register
4129 * Loop until in diagnostic mode
4130 */
4131 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4132 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4133 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4134 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4135 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4136 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4137
4138 /* wait 100 msec */
4139 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004140 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 } else {
4142 mdelay (100);
4143 }
4144
4145 count++;
4146 if (count > 20) {
4147 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4148 ioc->name, diag0val);
4149 break;
4150 }
4151 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4152 }
4153 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4154 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4155 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4156 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4157 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4158 ioc->name);
4159 }
4160
4161 /* Disable Diagnostic Mode
4162 */
4163 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4164
4165 /* Check FW reload status flags.
4166 */
4167 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4168 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4169 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4170 ioc->name, diag0val);
4171 return -3;
4172 }
4173
Prakash, Sathya436ace72007-07-24 15:42:08 +05304174 if (ioc->debug_level & MPT_DEBUG) {
4175 if (ioc->alt_ioc)
4176 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4177 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180
4181 /*
4182 * Reset flag that says we've enabled event notification
4183 */
4184 ioc->facts.EventState = 0;
4185
4186 if (ioc->alt_ioc)
4187 ioc->alt_ioc->facts.EventState = 0;
4188
4189 return hard_reset_done;
4190}
4191
4192/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004193/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194 * SendIocReset - Send IOCReset request to MPT adapter.
4195 * @ioc: Pointer to MPT_ADAPTER structure
4196 * @reset_type: reset type, expected values are
4197 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004198 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 *
4200 * Send IOCReset request to the MPT adapter.
4201 *
4202 * Returns 0 for success, non-zero for failure.
4203 */
4204static int
4205SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4206{
4207 int r;
4208 u32 state;
4209 int cntdn, count;
4210
Prakash, Sathya436ace72007-07-24 15:42:08 +05304211 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212 ioc->name, reset_type));
4213 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4214 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4215 return r;
4216
4217 /* FW ACK'd request, wait for READY state
4218 */
4219 count = 0;
4220 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4221
4222 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4223 cntdn--;
4224 count++;
4225 if (!cntdn) {
4226 if (sleepFlag != CAN_SLEEP)
4227 count *= 10;
4228
Kashyap, Desai2f187862009-05-29 16:52:37 +05304229 printk(MYIOC_s_ERR_FMT
4230 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
4231 ioc->name, state, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232 return -ETIME;
4233 }
4234
4235 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004236 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237 } else {
4238 mdelay (1); /* 1 msec delay */
4239 }
4240 }
4241
4242 /* TODO!
4243 * Cleanup all event stuff for this IOC; re-issue EventNotification
4244 * request if needed.
4245 */
4246 if (ioc->facts.Function)
4247 ioc->facts.EventState = 0;
4248
4249 return 0;
4250}
4251
4252/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004253/**
4254 * initChainBuffers - Allocate memory for and initialize chain buffers
4255 * @ioc: Pointer to MPT_ADAPTER structure
4256 *
4257 * Allocates memory for and initializes chain buffers,
4258 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259 */
4260static int
4261initChainBuffers(MPT_ADAPTER *ioc)
4262{
4263 u8 *mem;
4264 int sz, ii, num_chain;
4265 int scale, num_sge, numSGE;
4266
4267 /* ReqToChain size must equal the req_depth
4268 * index = req_idx
4269 */
4270 if (ioc->ReqToChain == NULL) {
4271 sz = ioc->req_depth * sizeof(int);
4272 mem = kmalloc(sz, GFP_ATOMIC);
4273 if (mem == NULL)
4274 return -1;
4275
4276 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304277 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278 ioc->name, mem, sz));
4279 mem = kmalloc(sz, GFP_ATOMIC);
4280 if (mem == NULL)
4281 return -1;
4282
4283 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304284 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285 ioc->name, mem, sz));
4286 }
4287 for (ii = 0; ii < ioc->req_depth; ii++) {
4288 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4289 }
4290
4291 /* ChainToChain size must equal the total number
4292 * of chain buffers to be allocated.
4293 * index = chain_idx
4294 *
4295 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004296 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297 *
4298 * num_sge = num sge in request frame + last chain buffer
4299 * scale = num sge per chain buffer if no chain element
4300 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304301 scale = ioc->req_sz / ioc->SGE_size;
4302 if (ioc->sg_addr_size == sizeof(u64))
4303 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304305 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304307 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304309 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304311 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4312 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304314 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315 ioc->name, num_sge, numSGE));
4316
Kashyap, Desai2f187862009-05-29 16:52:37 +05304317 if (ioc->bus_type == FC) {
4318 if (numSGE > MPT_SCSI_FC_SG_DEPTH)
4319 numSGE = MPT_SCSI_FC_SG_DEPTH;
4320 } else {
4321 if (numSGE > MPT_SCSI_SG_DEPTH)
4322 numSGE = MPT_SCSI_SG_DEPTH;
4323 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324
4325 num_chain = 1;
4326 while (numSGE - num_sge > 0) {
4327 num_chain++;
4328 num_sge += (scale - 1);
4329 }
4330 num_chain++;
4331
Prakash, Sathya436ace72007-07-24 15:42:08 +05304332 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 ioc->name, numSGE, num_sge, num_chain));
4334
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004335 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 num_chain *= MPT_SCSI_CAN_QUEUE;
Anatolij Gustschinf1053a72009-12-12 14:52:21 +01004337 else if (ioc->bus_type == SAS)
4338 num_chain *= MPT_SAS_CAN_QUEUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339 else
4340 num_chain *= MPT_FC_CAN_QUEUE;
4341
4342 ioc->num_chain = num_chain;
4343
4344 sz = num_chain * sizeof(int);
4345 if (ioc->ChainToChain == NULL) {
4346 mem = kmalloc(sz, GFP_ATOMIC);
4347 if (mem == NULL)
4348 return -1;
4349
4350 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304351 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 ioc->name, mem, sz));
4353 } else {
4354 mem = (u8 *) ioc->ChainToChain;
4355 }
4356 memset(mem, 0xFF, sz);
4357 return num_chain;
4358}
4359
4360/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004361/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4363 * @ioc: Pointer to MPT_ADAPTER structure
4364 *
4365 * This routine allocates memory for the MPT reply and request frame
4366 * pools (if necessary), and primes the IOC reply FIFO with
4367 * reply frames.
4368 *
4369 * Returns 0 for success, non-zero for failure.
4370 */
4371static int
4372PrimeIocFifos(MPT_ADAPTER *ioc)
4373{
4374 MPT_FRAME_HDR *mf;
4375 unsigned long flags;
4376 dma_addr_t alloc_dma;
4377 u8 *mem;
4378 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304379 u64 dma_mask;
4380
4381 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382
4383 /* Prime reply FIFO... */
4384
4385 if (ioc->reply_frames == NULL) {
4386 if ( (num_chain = initChainBuffers(ioc)) < 0)
4387 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304388 /*
4389 * 1078 errata workaround for the 36GB limitation
4390 */
4391 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
Andrew Morton8e20ce92009-06-18 16:49:17 -07004392 ioc->dma_mask > DMA_BIT_MASK(35)) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304393 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4394 && !pci_set_consistent_dma_mask(ioc->pcidev,
4395 DMA_BIT_MASK(32))) {
Andrew Morton8e20ce92009-06-18 16:49:17 -07004396 dma_mask = DMA_BIT_MASK(35);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304397 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4398 "setting 35 bit addressing for "
4399 "Request/Reply/Chain and Sense Buffers\n",
4400 ioc->name));
4401 } else {
4402 /*Reseting DMA mask to 64 bit*/
4403 pci_set_dma_mask(ioc->pcidev,
4404 DMA_BIT_MASK(64));
4405 pci_set_consistent_dma_mask(ioc->pcidev,
4406 DMA_BIT_MASK(64));
4407
4408 printk(MYIOC_s_ERR_FMT
4409 "failed setting 35 bit addressing for "
4410 "Request/Reply/Chain and Sense Buffers\n",
4411 ioc->name);
4412 return -1;
4413 }
4414 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415
4416 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304417 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304419 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 ioc->name, reply_sz, reply_sz));
4421
4422 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304423 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304425 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426 ioc->name, sz, sz));
4427 total_size += sz;
4428
4429 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304430 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304432 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433 ioc->name, sz, sz, num_chain));
4434
4435 total_size += sz;
4436 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4437 if (mem == NULL) {
4438 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4439 ioc->name);
4440 goto out_fail;
4441 }
4442
Prakash, Sathya436ace72007-07-24 15:42:08 +05304443 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4445
4446 memset(mem, 0, total_size);
4447 ioc->alloc_total += total_size;
4448 ioc->alloc = mem;
4449 ioc->alloc_dma = alloc_dma;
4450 ioc->alloc_sz = total_size;
4451 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4452 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4453
Prakash, Sathya436ace72007-07-24 15:42:08 +05304454 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004455 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4456
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457 alloc_dma += reply_sz;
4458 mem += reply_sz;
4459
4460 /* Request FIFO - WE manage this! */
4461
4462 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4463 ioc->req_frames_dma = alloc_dma;
4464
Prakash, Sathya436ace72007-07-24 15:42:08 +05304465 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 ioc->name, mem, (void *)(ulong)alloc_dma));
4467
4468 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4469
4470#if defined(CONFIG_MTRR) && 0
4471 /*
4472 * Enable Write Combining MTRR for IOC's memory region.
4473 * (at least as much as we can; "size and base must be
4474 * multiples of 4 kiB"
4475 */
4476 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4477 sz,
4478 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304479 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480 ioc->name, ioc->req_frames_dma, sz));
4481#endif
4482
4483 for (i = 0; i < ioc->req_depth; i++) {
4484 alloc_dma += ioc->req_sz;
4485 mem += ioc->req_sz;
4486 }
4487
4488 ioc->ChainBuffer = mem;
4489 ioc->ChainBufferDMA = alloc_dma;
4490
Prakash, Sathya436ace72007-07-24 15:42:08 +05304491 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4493
4494 /* Initialize the free chain Q.
4495 */
4496
4497 INIT_LIST_HEAD(&ioc->FreeChainQ);
4498
4499 /* Post the chain buffers to the FreeChainQ.
4500 */
4501 mem = (u8 *)ioc->ChainBuffer;
4502 for (i=0; i < num_chain; i++) {
4503 mf = (MPT_FRAME_HDR *) mem;
4504 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4505 mem += ioc->req_sz;
4506 }
4507
4508 /* Initialize Request frames linked list
4509 */
4510 alloc_dma = ioc->req_frames_dma;
4511 mem = (u8 *) ioc->req_frames;
4512
4513 spin_lock_irqsave(&ioc->FreeQlock, flags);
4514 INIT_LIST_HEAD(&ioc->FreeQ);
4515 for (i = 0; i < ioc->req_depth; i++) {
4516 mf = (MPT_FRAME_HDR *) mem;
4517
4518 /* Queue REQUESTs *internally*! */
4519 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4520
4521 mem += ioc->req_sz;
4522 }
4523 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4524
4525 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4526 ioc->sense_buf_pool =
4527 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4528 if (ioc->sense_buf_pool == NULL) {
4529 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4530 ioc->name);
4531 goto out_fail;
4532 }
4533
4534 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4535 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304536 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4538
4539 }
4540
4541 /* Post Reply frames to FIFO
4542 */
4543 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304544 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4546
4547 for (i = 0; i < ioc->reply_depth; i++) {
4548 /* Write each address to the IOC! */
4549 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4550 alloc_dma += ioc->reply_sz;
4551 }
4552
Andrew Morton8e20ce92009-06-18 16:49:17 -07004553 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304554 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4555 ioc->dma_mask))
4556 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4557 "restoring 64 bit addressing\n", ioc->name));
4558
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559 return 0;
4560
4561out_fail:
Kashyap, Desai2f187862009-05-29 16:52:37 +05304562
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 if (ioc->alloc != NULL) {
4564 sz = ioc->alloc_sz;
4565 pci_free_consistent(ioc->pcidev,
4566 sz,
4567 ioc->alloc, ioc->alloc_dma);
4568 ioc->reply_frames = NULL;
4569 ioc->req_frames = NULL;
4570 ioc->alloc_total -= sz;
4571 }
4572 if (ioc->sense_buf_pool != NULL) {
4573 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4574 pci_free_consistent(ioc->pcidev,
4575 sz,
4576 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4577 ioc->sense_buf_pool = NULL;
4578 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304579
Andrew Morton8e20ce92009-06-18 16:49:17 -07004580 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304581 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4582 DMA_BIT_MASK(64)))
4583 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4584 "restoring 64 bit addressing\n", ioc->name));
4585
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 return -1;
4587}
4588
4589/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4590/**
4591 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4592 * from IOC via doorbell handshake method.
4593 * @ioc: Pointer to MPT_ADAPTER structure
4594 * @reqBytes: Size of the request in bytes
4595 * @req: Pointer to MPT request frame
4596 * @replyBytes: Expected size of the reply in bytes
4597 * @u16reply: Pointer to area where reply should be written
4598 * @maxwait: Max wait time for a reply (in seconds)
4599 * @sleepFlag: Specifies whether the process can sleep
4600 *
4601 * NOTES: It is the callers responsibility to byte-swap fields in the
4602 * request which are greater than 1 byte in size. It is also the
4603 * callers responsibility to byte-swap response fields which are
4604 * greater than 1 byte in size.
4605 *
4606 * Returns 0 for success, non-zero for failure.
4607 */
4608static int
4609mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004610 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611{
4612 MPIDefaultReply_t *mptReply;
4613 int failcnt = 0;
4614 int t;
4615
4616 /*
4617 * Get ready to cache a handshake reply
4618 */
4619 ioc->hs_reply_idx = 0;
4620 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4621 mptReply->MsgLength = 0;
4622
4623 /*
4624 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4625 * then tell IOC that we want to handshake a request of N words.
4626 * (WRITE u32val to Doorbell reg).
4627 */
4628 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4629 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4630 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4631 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4632
4633 /*
4634 * Wait for IOC's doorbell handshake int
4635 */
4636 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4637 failcnt++;
4638
Prakash, Sathya436ace72007-07-24 15:42:08 +05304639 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4641
4642 /* Read doorbell and check for active bit */
4643 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4644 return -1;
4645
4646 /*
4647 * Clear doorbell int (WRITE 0 to IntStatus reg),
4648 * then wait for IOC to ACKnowledge that it's ready for
4649 * our handshake request.
4650 */
4651 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4652 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4653 failcnt++;
4654
4655 if (!failcnt) {
4656 int ii;
4657 u8 *req_as_bytes = (u8 *) req;
4658
4659 /*
4660 * Stuff request words via doorbell handshake,
4661 * with ACK from IOC for each.
4662 */
4663 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4664 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4665 (req_as_bytes[(ii*4) + 1] << 8) |
4666 (req_as_bytes[(ii*4) + 2] << 16) |
4667 (req_as_bytes[(ii*4) + 3] << 24));
4668
4669 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4670 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4671 failcnt++;
4672 }
4673
Prakash, Sathya436ace72007-07-24 15:42:08 +05304674 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004675 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004676
Prakash, Sathya436ace72007-07-24 15:42:08 +05304677 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4679
4680 /*
4681 * Wait for completion of doorbell handshake reply from the IOC
4682 */
4683 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4684 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004685
Prakash, Sathya436ace72007-07-24 15:42:08 +05304686 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4688
4689 /*
4690 * Copy out the cached reply...
4691 */
4692 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4693 u16reply[ii] = ioc->hs_reply[ii];
4694 } else {
4695 return -99;
4696 }
4697
4698 return -failcnt;
4699}
4700
4701/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004702/**
4703 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704 * @ioc: Pointer to MPT_ADAPTER structure
4705 * @howlong: How long to wait (in seconds)
4706 * @sleepFlag: Specifies whether the process can sleep
4707 *
4708 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004709 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4710 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711 *
4712 * Returns a negative value on failure, else wait loop count.
4713 */
4714static int
4715WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4716{
4717 int cntdn;
4718 int count = 0;
4719 u32 intstat=0;
4720
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004721 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722
4723 if (sleepFlag == CAN_SLEEP) {
4724 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004725 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4727 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4728 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729 count++;
4730 }
4731 } else {
4732 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004733 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4735 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4736 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737 count++;
4738 }
4739 }
4740
4741 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304742 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743 ioc->name, count));
4744 return count;
4745 }
4746
4747 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4748 ioc->name, count, intstat);
4749 return -1;
4750}
4751
4752/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004753/**
4754 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 * @ioc: Pointer to MPT_ADAPTER structure
4756 * @howlong: How long to wait (in seconds)
4757 * @sleepFlag: Specifies whether the process can sleep
4758 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004759 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4760 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761 *
4762 * Returns a negative value on failure, else wait loop count.
4763 */
4764static int
4765WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4766{
4767 int cntdn;
4768 int count = 0;
4769 u32 intstat=0;
4770
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004771 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772 if (sleepFlag == CAN_SLEEP) {
4773 while (--cntdn) {
4774 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4775 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4776 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004777 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778 count++;
4779 }
4780 } else {
4781 while (--cntdn) {
4782 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4783 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4784 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004785 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786 count++;
4787 }
4788 }
4789
4790 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304791 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792 ioc->name, count, howlong));
4793 return count;
4794 }
4795
4796 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4797 ioc->name, count, intstat);
4798 return -1;
4799}
4800
4801/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004802/**
4803 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804 * @ioc: Pointer to MPT_ADAPTER structure
4805 * @howlong: How long to wait (in seconds)
4806 * @sleepFlag: Specifies whether the process can sleep
4807 *
4808 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4809 * Reply is cached to IOC private area large enough to hold a maximum
4810 * of 128 bytes of reply data.
4811 *
4812 * Returns a negative value on failure, else size of reply in WORDS.
4813 */
4814static int
4815WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4816{
4817 int u16cnt = 0;
4818 int failcnt = 0;
4819 int t;
4820 u16 *hs_reply = ioc->hs_reply;
4821 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4822 u16 hword;
4823
4824 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4825
4826 /*
4827 * Get first two u16's so we can look at IOC's intended reply MsgLength
4828 */
4829 u16cnt=0;
4830 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4831 failcnt++;
4832 } else {
4833 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4834 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4835 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4836 failcnt++;
4837 else {
4838 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4839 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4840 }
4841 }
4842
Prakash, Sathya436ace72007-07-24 15:42:08 +05304843 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004844 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4846
4847 /*
4848 * If no error (and IOC said MsgLength is > 0), piece together
4849 * reply 16 bits at a time.
4850 */
4851 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4852 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4853 failcnt++;
4854 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4855 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004856 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857 hs_reply[u16cnt] = hword;
4858 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4859 }
4860
4861 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4862 failcnt++;
4863 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4864
4865 if (failcnt) {
4866 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4867 ioc->name);
4868 return -failcnt;
4869 }
4870#if 0
4871 else if (u16cnt != (2 * mptReply->MsgLength)) {
4872 return -101;
4873 }
4874 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4875 return -102;
4876 }
4877#endif
4878
Prakash, Sathya436ace72007-07-24 15:42:08 +05304879 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004880 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881
Prakash, Sathya436ace72007-07-24 15:42:08 +05304882 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 ioc->name, t, u16cnt/2));
4884 return u16cnt/2;
4885}
4886
4887/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004888/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889 * GetLanConfigPages - Fetch LANConfig pages.
4890 * @ioc: Pointer to MPT_ADAPTER structure
4891 *
4892 * Return: 0 for success
4893 * -ENOMEM if no memory available
4894 * -EPERM if not allowed due to ISR context
4895 * -EAGAIN if no msg frames currently available
4896 * -EFAULT for non-successful reply or no reply (timeout)
4897 */
4898static int
4899GetLanConfigPages(MPT_ADAPTER *ioc)
4900{
4901 ConfigPageHeader_t hdr;
4902 CONFIGPARMS cfg;
4903 LANPage0_t *ppage0_alloc;
4904 dma_addr_t page0_dma;
4905 LANPage1_t *ppage1_alloc;
4906 dma_addr_t page1_dma;
4907 int rc = 0;
4908 int data_sz;
4909 int copy_sz;
4910
4911 /* Get LAN Page 0 header */
4912 hdr.PageVersion = 0;
4913 hdr.PageLength = 0;
4914 hdr.PageNumber = 0;
4915 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004916 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917 cfg.physAddr = -1;
4918 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4919 cfg.dir = 0;
4920 cfg.pageAddr = 0;
4921 cfg.timeout = 0;
4922
4923 if ((rc = mpt_config(ioc, &cfg)) != 0)
4924 return rc;
4925
4926 if (hdr.PageLength > 0) {
4927 data_sz = hdr.PageLength * 4;
4928 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4929 rc = -ENOMEM;
4930 if (ppage0_alloc) {
4931 memset((u8 *)ppage0_alloc, 0, data_sz);
4932 cfg.physAddr = page0_dma;
4933 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4934
4935 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4936 /* save the data */
4937 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4938 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4939
4940 }
4941
4942 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4943
4944 /* FIXME!
4945 * Normalize endianness of structure data,
4946 * by byte-swapping all > 1 byte fields!
4947 */
4948
4949 }
4950
4951 if (rc)
4952 return rc;
4953 }
4954
4955 /* Get LAN Page 1 header */
4956 hdr.PageVersion = 0;
4957 hdr.PageLength = 0;
4958 hdr.PageNumber = 1;
4959 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004960 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004961 cfg.physAddr = -1;
4962 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4963 cfg.dir = 0;
4964 cfg.pageAddr = 0;
4965
4966 if ((rc = mpt_config(ioc, &cfg)) != 0)
4967 return rc;
4968
4969 if (hdr.PageLength == 0)
4970 return 0;
4971
4972 data_sz = hdr.PageLength * 4;
4973 rc = -ENOMEM;
4974 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4975 if (ppage1_alloc) {
4976 memset((u8 *)ppage1_alloc, 0, data_sz);
4977 cfg.physAddr = page1_dma;
4978 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4979
4980 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4981 /* save the data */
4982 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4983 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4984 }
4985
4986 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4987
4988 /* FIXME!
4989 * Normalize endianness of structure data,
4990 * by byte-swapping all > 1 byte fields!
4991 */
4992
4993 }
4994
4995 return rc;
4996}
4997
4998/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004999/**
5000 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005001 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005002 * @persist_opcode: see below
5003 *
5004 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
5005 * devices not currently present.
5006 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
5007 *
5008 * NOTE: Don't use not this function during interrupt time.
5009 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005010 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005011 */
5012
5013/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5014int
5015mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
5016{
5017 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
5018 SasIoUnitControlReply_t *sasIoUnitCntrReply;
5019 MPT_FRAME_HDR *mf = NULL;
5020 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305021 int ret = 0;
5022 unsigned long timeleft;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005023
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305024 mutex_lock(&ioc->mptbase_cmds.mutex);
5025
5026 /* init the internal cmd struct */
5027 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
5028 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005029
5030 /* insure garbage is not sent to fw */
5031 switch(persist_opcode) {
5032
5033 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
5034 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
5035 break;
5036
5037 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305038 ret = -1;
5039 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005040 }
5041
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305042 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
5043 __func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005044
5045 /* Get a MF for this command.
5046 */
5047 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305048 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
5049 ret = -1;
5050 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005051 }
5052
5053 mpi_hdr = (MPIHeader_t *) mf;
5054 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
5055 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
5056 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
5057 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
5058 sasIoUnitCntrReq->Operation = persist_opcode;
5059
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005060 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305061 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
5062 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
5063 ret = -ETIME;
5064 printk(KERN_DEBUG "%s: failed\n", __func__);
5065 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
5066 goto out;
5067 if (!timeleft) {
5068 printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n",
5069 ioc->name, __func__);
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05305070 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305071 mpt_free_msg_frame(ioc, mf);
5072 }
5073 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005074 }
5075
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305076 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
5077 ret = -1;
5078 goto out;
5079 }
5080
5081 sasIoUnitCntrReply =
5082 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5083 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5084 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5085 __func__, sasIoUnitCntrReply->IOCStatus,
5086 sasIoUnitCntrReply->IOCLogInfo);
5087 printk(KERN_DEBUG "%s: failed\n", __func__);
5088 ret = -1;
5089 } else
5090 printk(KERN_DEBUG "%s: success\n", __func__);
5091 out:
5092
5093 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5094 mutex_unlock(&ioc->mptbase_cmds.mutex);
5095 return ret;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005096}
5097
5098/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005099
5100static void
5101mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5102 MpiEventDataRaid_t * pRaidEventData)
5103{
5104 int volume;
5105 int reason;
5106 int disk;
5107 int status;
5108 int flags;
5109 int state;
5110
5111 volume = pRaidEventData->VolumeID;
5112 reason = pRaidEventData->ReasonCode;
5113 disk = pRaidEventData->PhysDiskNum;
5114 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5115 flags = (status >> 0) & 0xff;
5116 state = (status >> 8) & 0xff;
5117
5118 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5119 return;
5120 }
5121
5122 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5123 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5124 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005125 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5126 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005127 } else {
5128 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5129 ioc->name, volume);
5130 }
5131
5132 switch(reason) {
5133 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5134 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5135 ioc->name);
5136 break;
5137
5138 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5139
5140 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5141 ioc->name);
5142 break;
5143
5144 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5145 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5146 ioc->name);
5147 break;
5148
5149 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5150 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5151 ioc->name,
5152 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5153 ? "optimal"
5154 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5155 ? "degraded"
5156 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5157 ? "failed"
5158 : "state unknown",
5159 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5160 ? ", enabled" : "",
5161 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5162 ? ", quiesced" : "",
5163 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5164 ? ", resync in progress" : "" );
5165 break;
5166
5167 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5168 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5169 ioc->name, disk);
5170 break;
5171
5172 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5173 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5174 ioc->name);
5175 break;
5176
5177 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5178 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5179 ioc->name);
5180 break;
5181
5182 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5183 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5184 ioc->name);
5185 break;
5186
5187 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5188 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5189 ioc->name,
5190 state == MPI_PHYSDISK0_STATUS_ONLINE
5191 ? "online"
5192 : state == MPI_PHYSDISK0_STATUS_MISSING
5193 ? "missing"
5194 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5195 ? "not compatible"
5196 : state == MPI_PHYSDISK0_STATUS_FAILED
5197 ? "failed"
5198 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5199 ? "initializing"
5200 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5201 ? "offline requested"
5202 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5203 ? "failed requested"
5204 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5205 ? "offline"
5206 : "state unknown",
5207 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5208 ? ", out of sync" : "",
5209 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5210 ? ", quiesced" : "" );
5211 break;
5212
5213 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5214 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5215 ioc->name, disk);
5216 break;
5217
5218 case MPI_EVENT_RAID_RC_SMART_DATA:
5219 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5220 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5221 break;
5222
5223 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5224 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5225 ioc->name, disk);
5226 break;
5227 }
5228}
5229
5230/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005231/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5233 * @ioc: Pointer to MPT_ADAPTER structure
5234 *
5235 * Returns: 0 for success
5236 * -ENOMEM if no memory available
5237 * -EPERM if not allowed due to ISR context
5238 * -EAGAIN if no msg frames currently available
5239 * -EFAULT for non-successful reply or no reply (timeout)
5240 */
5241static int
5242GetIoUnitPage2(MPT_ADAPTER *ioc)
5243{
5244 ConfigPageHeader_t hdr;
5245 CONFIGPARMS cfg;
5246 IOUnitPage2_t *ppage_alloc;
5247 dma_addr_t page_dma;
5248 int data_sz;
5249 int rc;
5250
5251 /* Get the page header */
5252 hdr.PageVersion = 0;
5253 hdr.PageLength = 0;
5254 hdr.PageNumber = 2;
5255 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005256 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005257 cfg.physAddr = -1;
5258 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5259 cfg.dir = 0;
5260 cfg.pageAddr = 0;
5261 cfg.timeout = 0;
5262
5263 if ((rc = mpt_config(ioc, &cfg)) != 0)
5264 return rc;
5265
5266 if (hdr.PageLength == 0)
5267 return 0;
5268
5269 /* Read the config page */
5270 data_sz = hdr.PageLength * 4;
5271 rc = -ENOMEM;
5272 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5273 if (ppage_alloc) {
5274 memset((u8 *)ppage_alloc, 0, data_sz);
5275 cfg.physAddr = page_dma;
5276 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5277
5278 /* If Good, save data */
5279 if ((rc = mpt_config(ioc, &cfg)) == 0)
5280 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5281
5282 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5283 }
5284
5285 return rc;
5286}
5287
5288/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005289/**
5290 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291 * @ioc: Pointer to a Adapter Strucutre
5292 * @portnum: IOC port number
5293 *
5294 * Return: -EFAULT if read of config page header fails
5295 * or if no nvram
5296 * If read of SCSI Port Page 0 fails,
5297 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5298 * Adapter settings: async, narrow
5299 * Return 1
5300 * If read of SCSI Port Page 2 fails,
5301 * Adapter settings valid
5302 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5303 * Return 1
5304 * Else
5305 * Both valid
5306 * Return 0
5307 * CHECK - what type of locking mechanisms should be used????
5308 */
5309static int
5310mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5311{
5312 u8 *pbuf;
5313 dma_addr_t buf_dma;
5314 CONFIGPARMS cfg;
5315 ConfigPageHeader_t header;
5316 int ii;
5317 int data, rc = 0;
5318
5319 /* Allocate memory
5320 */
5321 if (!ioc->spi_data.nvram) {
5322 int sz;
5323 u8 *mem;
5324 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5325 mem = kmalloc(sz, GFP_ATOMIC);
5326 if (mem == NULL)
5327 return -EFAULT;
5328
5329 ioc->spi_data.nvram = (int *) mem;
5330
Prakash, Sathya436ace72007-07-24 15:42:08 +05305331 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005332 ioc->name, ioc->spi_data.nvram, sz));
5333 }
5334
5335 /* Invalidate NVRAM information
5336 */
5337 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5338 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5339 }
5340
5341 /* Read SPP0 header, allocate memory, then read page.
5342 */
5343 header.PageVersion = 0;
5344 header.PageLength = 0;
5345 header.PageNumber = 0;
5346 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005347 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005348 cfg.physAddr = -1;
5349 cfg.pageAddr = portnum;
5350 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5351 cfg.dir = 0;
5352 cfg.timeout = 0; /* use default */
5353 if (mpt_config(ioc, &cfg) != 0)
5354 return -EFAULT;
5355
5356 if (header.PageLength > 0) {
5357 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5358 if (pbuf) {
5359 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5360 cfg.physAddr = buf_dma;
5361 if (mpt_config(ioc, &cfg) != 0) {
5362 ioc->spi_data.maxBusWidth = MPT_NARROW;
5363 ioc->spi_data.maxSyncOffset = 0;
5364 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5365 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5366 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305367 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5368 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005369 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005370 } else {
5371 /* Save the Port Page 0 data
5372 */
5373 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5374 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5375 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5376
5377 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5378 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005379 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5380 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381 ioc->name, pPP0->Capabilities));
5382 }
5383 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5384 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5385 if (data) {
5386 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5387 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5388 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305389 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5390 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005391 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 } else {
5393 ioc->spi_data.maxSyncOffset = 0;
5394 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5395 }
5396
5397 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5398
5399 /* Update the minSyncFactor based on bus type.
5400 */
5401 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5402 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5403
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005404 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305406 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5407 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005408 ioc->name, ioc->spi_data.minSyncFactor));
5409 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410 }
5411 }
5412 if (pbuf) {
5413 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5414 }
5415 }
5416 }
5417
5418 /* SCSI Port Page 2 - Read the header then the page.
5419 */
5420 header.PageVersion = 0;
5421 header.PageLength = 0;
5422 header.PageNumber = 2;
5423 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005424 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005425 cfg.physAddr = -1;
5426 cfg.pageAddr = portnum;
5427 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5428 cfg.dir = 0;
5429 if (mpt_config(ioc, &cfg) != 0)
5430 return -EFAULT;
5431
5432 if (header.PageLength > 0) {
5433 /* Allocate memory and read SCSI Port Page 2
5434 */
5435 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5436 if (pbuf) {
5437 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5438 cfg.physAddr = buf_dma;
5439 if (mpt_config(ioc, &cfg) != 0) {
5440 /* Nvram data is left with INVALID mark
5441 */
5442 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005443 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5444
5445 /* This is an ATTO adapter, read Page2 accordingly
5446 */
5447 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5448 ATTODeviceInfo_t *pdevice = NULL;
5449 u16 ATTOFlags;
5450
5451 /* Save the Port Page 2 data
5452 * (reformat into a 32bit quantity)
5453 */
5454 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5455 pdevice = &pPP2->DeviceSettings[ii];
5456 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5457 data = 0;
5458
5459 /* Translate ATTO device flags to LSI format
5460 */
5461 if (ATTOFlags & ATTOFLAG_DISC)
5462 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5463 if (ATTOFlags & ATTOFLAG_ID_ENB)
5464 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5465 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5466 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5467 if (ATTOFlags & ATTOFLAG_TAGGED)
5468 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5469 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5470 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5471
5472 data = (data << 16) | (pdevice->Period << 8) | 10;
5473 ioc->spi_data.nvram[ii] = data;
5474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 } else {
5476 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5477 MpiDeviceInfo_t *pdevice = NULL;
5478
Moore, Ericd8e925d2006-01-16 18:53:06 -07005479 /*
5480 * Save "Set to Avoid SCSI Bus Resets" flag
5481 */
5482 ioc->spi_data.bus_reset =
5483 (le32_to_cpu(pPP2->PortFlags) &
5484 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5485 0 : 1 ;
5486
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487 /* Save the Port Page 2 data
5488 * (reformat into a 32bit quantity)
5489 */
5490 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5491 ioc->spi_data.PortFlags = data;
5492 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5493 pdevice = &pPP2->DeviceSettings[ii];
5494 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5495 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5496 ioc->spi_data.nvram[ii] = data;
5497 }
5498 }
5499
5500 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5501 }
5502 }
5503
5504 /* Update Adapter limits with those from NVRAM
5505 * Comment: Don't need to do this. Target performance
5506 * parameters will never exceed the adapters limits.
5507 */
5508
5509 return rc;
5510}
5511
5512/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005513/**
5514 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515 * @ioc: Pointer to a Adapter Strucutre
5516 * @portnum: IOC port number
5517 *
5518 * Return: -EFAULT if read of config page header fails
5519 * or 0 if success.
5520 */
5521static int
5522mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5523{
5524 CONFIGPARMS cfg;
5525 ConfigPageHeader_t header;
5526
5527 /* Read the SCSI Device Page 1 header
5528 */
5529 header.PageVersion = 0;
5530 header.PageLength = 0;
5531 header.PageNumber = 1;
5532 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005533 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 cfg.physAddr = -1;
5535 cfg.pageAddr = portnum;
5536 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5537 cfg.dir = 0;
5538 cfg.timeout = 0;
5539 if (mpt_config(ioc, &cfg) != 0)
5540 return -EFAULT;
5541
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005542 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5543 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544
5545 header.PageVersion = 0;
5546 header.PageLength = 0;
5547 header.PageNumber = 0;
5548 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5549 if (mpt_config(ioc, &cfg) != 0)
5550 return -EFAULT;
5551
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005552 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5553 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554
Prakash, Sathya436ace72007-07-24 15:42:08 +05305555 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5557
Prakash, Sathya436ace72007-07-24 15:42:08 +05305558 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5560 return 0;
5561}
5562
Eric Mooreb506ade2007-01-29 09:45:37 -07005563/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005564 * mpt_inactive_raid_list_free - This clears this link list.
5565 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005566 **/
5567static void
5568mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5569{
5570 struct inactive_raid_component_info *component_info, *pNext;
5571
5572 if (list_empty(&ioc->raid_data.inactive_list))
5573 return;
5574
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005575 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005576 list_for_each_entry_safe(component_info, pNext,
5577 &ioc->raid_data.inactive_list, list) {
5578 list_del(&component_info->list);
5579 kfree(component_info);
5580 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005581 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005582}
5583
5584/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005585 * 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 -07005586 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005587 * @ioc : pointer to per adapter structure
5588 * @channel : volume channel
5589 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005590 **/
5591static void
5592mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5593{
5594 CONFIGPARMS cfg;
5595 ConfigPageHeader_t hdr;
5596 dma_addr_t dma_handle;
5597 pRaidVolumePage0_t buffer = NULL;
5598 int i;
5599 RaidPhysDiskPage0_t phys_disk;
5600 struct inactive_raid_component_info *component_info;
5601 int handle_inactive_volumes;
5602
5603 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5604 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5605 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5606 cfg.pageAddr = (channel << 8) + id;
5607 cfg.cfghdr.hdr = &hdr;
5608 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5609
5610 if (mpt_config(ioc, &cfg) != 0)
5611 goto out;
5612
5613 if (!hdr.PageLength)
5614 goto out;
5615
5616 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5617 &dma_handle);
5618
5619 if (!buffer)
5620 goto out;
5621
5622 cfg.physAddr = dma_handle;
5623 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5624
5625 if (mpt_config(ioc, &cfg) != 0)
5626 goto out;
5627
5628 if (!buffer->NumPhysDisks)
5629 goto out;
5630
5631 handle_inactive_volumes =
5632 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5633 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5634 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5635 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5636
5637 if (!handle_inactive_volumes)
5638 goto out;
5639
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005640 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005641 for (i = 0; i < buffer->NumPhysDisks; i++) {
5642 if(mpt_raid_phys_disk_pg0(ioc,
5643 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5644 continue;
5645
5646 if ((component_info = kmalloc(sizeof (*component_info),
5647 GFP_KERNEL)) == NULL)
5648 continue;
5649
5650 component_info->volumeID = id;
5651 component_info->volumeBus = channel;
5652 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5653 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5654 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5655 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5656
5657 list_add_tail(&component_info->list,
5658 &ioc->raid_data.inactive_list);
5659 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005660 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005661
5662 out:
5663 if (buffer)
5664 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5665 dma_handle);
5666}
5667
5668/**
5669 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5670 * @ioc: Pointer to a Adapter Structure
5671 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5672 * @phys_disk: requested payload data returned
5673 *
5674 * Return:
5675 * 0 on success
5676 * -EFAULT if read of config page header fails or data pointer not NULL
5677 * -ENOMEM if pci_alloc failed
5678 **/
5679int
Kashyap, Desai2f187862009-05-29 16:52:37 +05305680mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
5681 RaidPhysDiskPage0_t *phys_disk)
Eric Mooreb506ade2007-01-29 09:45:37 -07005682{
Kashyap, Desai2f187862009-05-29 16:52:37 +05305683 CONFIGPARMS cfg;
5684 ConfigPageHeader_t hdr;
Eric Mooreb506ade2007-01-29 09:45:37 -07005685 dma_addr_t dma_handle;
5686 pRaidPhysDiskPage0_t buffer = NULL;
5687 int rc;
5688
5689 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5690 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
Kashyap, Desai2f187862009-05-29 16:52:37 +05305691 memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
Eric Mooreb506ade2007-01-29 09:45:37 -07005692
Kashyap, Desai2f187862009-05-29 16:52:37 +05305693 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
Eric Mooreb506ade2007-01-29 09:45:37 -07005694 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5695 cfg.cfghdr.hdr = &hdr;
5696 cfg.physAddr = -1;
5697 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5698
5699 if (mpt_config(ioc, &cfg) != 0) {
5700 rc = -EFAULT;
5701 goto out;
5702 }
5703
5704 if (!hdr.PageLength) {
5705 rc = -EFAULT;
5706 goto out;
5707 }
5708
5709 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5710 &dma_handle);
5711
5712 if (!buffer) {
5713 rc = -ENOMEM;
5714 goto out;
5715 }
5716
5717 cfg.physAddr = dma_handle;
5718 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5719 cfg.pageAddr = phys_disk_num;
5720
5721 if (mpt_config(ioc, &cfg) != 0) {
5722 rc = -EFAULT;
5723 goto out;
5724 }
5725
5726 rc = 0;
5727 memcpy(phys_disk, buffer, sizeof(*buffer));
5728 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5729
5730 out:
5731
5732 if (buffer)
5733 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5734 dma_handle);
5735
5736 return rc;
5737}
5738
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739/**
Kashyap, Desaia7938b02009-05-29 16:53:56 +05305740 * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
5741 * @ioc: Pointer to a Adapter Structure
5742 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5743 *
5744 * Return:
5745 * returns number paths
5746 **/
5747int
5748mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
5749{
5750 CONFIGPARMS cfg;
5751 ConfigPageHeader_t hdr;
5752 dma_addr_t dma_handle;
5753 pRaidPhysDiskPage1_t buffer = NULL;
5754 int rc;
5755
5756 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5757 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5758
5759 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5760 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5761 hdr.PageNumber = 1;
5762 cfg.cfghdr.hdr = &hdr;
5763 cfg.physAddr = -1;
5764 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5765
5766 if (mpt_config(ioc, &cfg) != 0) {
5767 rc = 0;
5768 goto out;
5769 }
5770
5771 if (!hdr.PageLength) {
5772 rc = 0;
5773 goto out;
5774 }
5775
5776 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5777 &dma_handle);
5778
5779 if (!buffer) {
5780 rc = 0;
5781 goto out;
5782 }
5783
5784 cfg.physAddr = dma_handle;
5785 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5786 cfg.pageAddr = phys_disk_num;
5787
5788 if (mpt_config(ioc, &cfg) != 0) {
5789 rc = 0;
5790 goto out;
5791 }
5792
5793 rc = buffer->NumPhysDiskPaths;
5794 out:
5795
5796 if (buffer)
5797 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5798 dma_handle);
5799
5800 return rc;
5801}
5802EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
5803
5804/**
5805 * mpt_raid_phys_disk_pg1 - returns phys disk page 1
5806 * @ioc: Pointer to a Adapter Structure
5807 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5808 * @phys_disk: requested payload data returned
5809 *
5810 * Return:
5811 * 0 on success
5812 * -EFAULT if read of config page header fails or data pointer not NULL
5813 * -ENOMEM if pci_alloc failed
5814 **/
5815int
5816mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
5817 RaidPhysDiskPage1_t *phys_disk)
5818{
5819 CONFIGPARMS cfg;
5820 ConfigPageHeader_t hdr;
5821 dma_addr_t dma_handle;
5822 pRaidPhysDiskPage1_t buffer = NULL;
5823 int rc;
5824 int i;
5825 __le64 sas_address;
5826
5827 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5828 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5829 rc = 0;
5830
5831 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5832 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5833 hdr.PageNumber = 1;
5834 cfg.cfghdr.hdr = &hdr;
5835 cfg.physAddr = -1;
5836 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5837
5838 if (mpt_config(ioc, &cfg) != 0) {
5839 rc = -EFAULT;
5840 goto out;
5841 }
5842
5843 if (!hdr.PageLength) {
5844 rc = -EFAULT;
5845 goto out;
5846 }
5847
5848 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5849 &dma_handle);
5850
5851 if (!buffer) {
5852 rc = -ENOMEM;
5853 goto out;
5854 }
5855
5856 cfg.physAddr = dma_handle;
5857 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5858 cfg.pageAddr = phys_disk_num;
5859
5860 if (mpt_config(ioc, &cfg) != 0) {
5861 rc = -EFAULT;
5862 goto out;
5863 }
5864
5865 phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
5866 phys_disk->PhysDiskNum = phys_disk_num;
5867 for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
5868 phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
5869 phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
5870 phys_disk->Path[i].OwnerIdentifier =
5871 buffer->Path[i].OwnerIdentifier;
5872 phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
5873 memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
5874 sas_address = le64_to_cpu(sas_address);
5875 memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
5876 memcpy(&sas_address,
5877 &buffer->Path[i].OwnerWWID, sizeof(__le64));
5878 sas_address = le64_to_cpu(sas_address);
5879 memcpy(&phys_disk->Path[i].OwnerWWID,
5880 &sas_address, sizeof(__le64));
5881 }
5882
5883 out:
5884
5885 if (buffer)
5886 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5887 dma_handle);
5888
5889 return rc;
5890}
5891EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
5892
5893
5894/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005895 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5896 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005897 *
5898 * Return:
5899 * 0 on success
5900 * -EFAULT if read of config page header fails or data pointer not NULL
5901 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005902 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005903int
5904mpt_findImVolumes(MPT_ADAPTER *ioc)
5905{
5906 IOCPage2_t *pIoc2;
5907 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908 dma_addr_t ioc2_dma;
5909 CONFIGPARMS cfg;
5910 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005911 int rc = 0;
5912 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005913 int i;
5914
5915 if (!ioc->ir_firmware)
5916 return 0;
5917
5918 /* Free the old page
5919 */
5920 kfree(ioc->raid_data.pIocPg2);
5921 ioc->raid_data.pIocPg2 = NULL;
5922 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005923
5924 /* Read IOCP2 header then the page.
5925 */
5926 header.PageVersion = 0;
5927 header.PageLength = 0;
5928 header.PageNumber = 2;
5929 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005930 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931 cfg.physAddr = -1;
5932 cfg.pageAddr = 0;
5933 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5934 cfg.dir = 0;
5935 cfg.timeout = 0;
5936 if (mpt_config(ioc, &cfg) != 0)
5937 return -EFAULT;
5938
5939 if (header.PageLength == 0)
5940 return -EFAULT;
5941
5942 iocpage2sz = header.PageLength * 4;
5943 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5944 if (!pIoc2)
5945 return -ENOMEM;
5946
5947 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5948 cfg.physAddr = ioc2_dma;
5949 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005950 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005951
Eric Mooreb506ade2007-01-29 09:45:37 -07005952 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5953 if (!mem)
5954 goto out;
5955
Linus Torvalds1da177e2005-04-16 15:20:36 -07005956 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005957 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005958
Eric Mooreb506ade2007-01-29 09:45:37 -07005959 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960
Eric Mooreb506ade2007-01-29 09:45:37 -07005961 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5962 mpt_inactive_raid_volumes(ioc,
5963 pIoc2->RaidVolume[i].VolumeBus,
5964 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005965
Eric Mooreb506ade2007-01-29 09:45:37 -07005966 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5968
5969 return rc;
5970}
5971
Moore, Ericc972c702006-03-14 09:14:06 -07005972static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005973mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5974{
5975 IOCPage3_t *pIoc3;
5976 u8 *mem;
5977 CONFIGPARMS cfg;
5978 ConfigPageHeader_t header;
5979 dma_addr_t ioc3_dma;
5980 int iocpage3sz = 0;
5981
5982 /* Free the old page
5983 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005984 kfree(ioc->raid_data.pIocPg3);
5985 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986
5987 /* There is at least one physical disk.
5988 * Read and save IOC Page 3
5989 */
5990 header.PageVersion = 0;
5991 header.PageLength = 0;
5992 header.PageNumber = 3;
5993 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005994 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995 cfg.physAddr = -1;
5996 cfg.pageAddr = 0;
5997 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5998 cfg.dir = 0;
5999 cfg.timeout = 0;
6000 if (mpt_config(ioc, &cfg) != 0)
6001 return 0;
6002
6003 if (header.PageLength == 0)
6004 return 0;
6005
6006 /* Read Header good, alloc memory
6007 */
6008 iocpage3sz = header.PageLength * 4;
6009 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
6010 if (!pIoc3)
6011 return 0;
6012
6013 /* Read the Page and save the data
6014 * into malloc'd memory.
6015 */
6016 cfg.physAddr = ioc3_dma;
6017 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6018 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07006019 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006020 if (mem) {
6021 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006022 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006023 }
6024 }
6025
6026 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
6027
6028 return 0;
6029}
6030
6031static void
6032mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
6033{
6034 IOCPage4_t *pIoc4;
6035 CONFIGPARMS cfg;
6036 ConfigPageHeader_t header;
6037 dma_addr_t ioc4_dma;
6038 int iocpage4sz;
6039
6040 /* Read and save IOC Page 4
6041 */
6042 header.PageVersion = 0;
6043 header.PageLength = 0;
6044 header.PageNumber = 4;
6045 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006046 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006047 cfg.physAddr = -1;
6048 cfg.pageAddr = 0;
6049 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6050 cfg.dir = 0;
6051 cfg.timeout = 0;
6052 if (mpt_config(ioc, &cfg) != 0)
6053 return;
6054
6055 if (header.PageLength == 0)
6056 return;
6057
6058 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
6059 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
6060 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
6061 if (!pIoc4)
6062 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06006063 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064 } else {
6065 ioc4_dma = ioc->spi_data.IocPg4_dma;
6066 iocpage4sz = ioc->spi_data.IocPg4Sz;
6067 }
6068
6069 /* Read the Page into dma memory.
6070 */
6071 cfg.physAddr = ioc4_dma;
6072 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6073 if (mpt_config(ioc, &cfg) == 0) {
6074 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
6075 ioc->spi_data.IocPg4_dma = ioc4_dma;
6076 ioc->spi_data.IocPg4Sz = iocpage4sz;
6077 } else {
6078 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
6079 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06006080 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006081 }
6082}
6083
6084static void
6085mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
6086{
6087 IOCPage1_t *pIoc1;
6088 CONFIGPARMS cfg;
6089 ConfigPageHeader_t header;
6090 dma_addr_t ioc1_dma;
6091 int iocpage1sz = 0;
6092 u32 tmp;
6093
6094 /* Check the Coalescing Timeout in IOC Page 1
6095 */
6096 header.PageVersion = 0;
6097 header.PageLength = 0;
6098 header.PageNumber = 1;
6099 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006100 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006101 cfg.physAddr = -1;
6102 cfg.pageAddr = 0;
6103 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6104 cfg.dir = 0;
6105 cfg.timeout = 0;
6106 if (mpt_config(ioc, &cfg) != 0)
6107 return;
6108
6109 if (header.PageLength == 0)
6110 return;
6111
6112 /* Read Header good, alloc memory
6113 */
6114 iocpage1sz = header.PageLength * 4;
6115 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
6116 if (!pIoc1)
6117 return;
6118
6119 /* Read the Page and check coalescing timeout
6120 */
6121 cfg.physAddr = ioc1_dma;
6122 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6123 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306124
Linus Torvalds1da177e2005-04-16 15:20:36 -07006125 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
6126 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
6127 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
6128
Prakash, Sathya436ace72007-07-24 15:42:08 +05306129 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006130 ioc->name, tmp));
6131
6132 if (tmp > MPT_COALESCING_TIMEOUT) {
6133 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
6134
6135 /* Write NVRAM and current
6136 */
6137 cfg.dir = 1;
6138 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
6139 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306140 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141 ioc->name, MPT_COALESCING_TIMEOUT));
6142
6143 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
6144 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306145 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6146 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006147 ioc->name, MPT_COALESCING_TIMEOUT));
6148 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306149 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6150 "Reset NVRAM Coalescing Timeout Failed\n",
6151 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006152 }
6153
6154 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306155 dprintk(ioc, printk(MYIOC_s_WARN_FMT
6156 "Reset of Current Coalescing Timeout Failed!\n",
6157 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006158 }
6159 }
6160
6161 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306162 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006163 }
6164 }
6165
6166 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
6167
6168 return;
6169}
6170
Prakash, Sathyaedb90682007-07-17 14:39:14 +05306171static void
6172mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
6173{
6174 CONFIGPARMS cfg;
6175 ConfigPageHeader_t hdr;
6176 dma_addr_t buf_dma;
6177 ManufacturingPage0_t *pbuf = NULL;
6178
6179 memset(&cfg, 0 , sizeof(CONFIGPARMS));
6180 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
6181
6182 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
6183 cfg.cfghdr.hdr = &hdr;
6184 cfg.physAddr = -1;
6185 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6186 cfg.timeout = 10;
6187
6188 if (mpt_config(ioc, &cfg) != 0)
6189 goto out;
6190
6191 if (!cfg.cfghdr.hdr->PageLength)
6192 goto out;
6193
6194 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6195 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
6196 if (!pbuf)
6197 goto out;
6198
6199 cfg.physAddr = buf_dma;
6200
6201 if (mpt_config(ioc, &cfg) != 0)
6202 goto out;
6203
6204 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
6205 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
6206 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
6207
6208 out:
6209
6210 if (pbuf)
6211 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
6212}
6213
Linus Torvalds1da177e2005-04-16 15:20:36 -07006214/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006215/**
6216 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217 * @ioc: Pointer to MPT_ADAPTER structure
6218 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05306219 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07006220 */
6221static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05306222SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223{
Kashyap, Desaifd761752009-05-29 16:39:06 +05306224 EventNotification_t evn;
6225 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006226
Kashyap, Desaifd761752009-05-29 16:39:06 +05306227 memset(&evn, 0, sizeof(EventNotification_t));
6228 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006229
Kashyap, Desaifd761752009-05-29 16:39:06 +05306230 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
6231 evn.Switch = EvSwitch;
6232 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006233
Kashyap, Desaifd761752009-05-29 16:39:06 +05306234 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6235 "Sending EventNotification (%d) request %p\n",
6236 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006237
Kashyap, Desaifd761752009-05-29 16:39:06 +05306238 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6239 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6240 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241}
6242
6243/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6244/**
6245 * SendEventAck - Send EventAck request to MPT adapter.
6246 * @ioc: Pointer to MPT_ADAPTER structure
6247 * @evnp: Pointer to original EventNotification request
6248 */
6249static int
6250SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6251{
6252 EventAck_t *pAck;
6253
6254 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306255 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306256 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006257 return -1;
6258 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006259
Prakash, Sathya436ace72007-07-24 15:42:08 +05306260 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006261
6262 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6263 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006264 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006265 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006266 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006267 pAck->Event = evnp->Event;
6268 pAck->EventContext = evnp->EventContext;
6269
6270 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6271
6272 return 0;
6273}
6274
6275/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6276/**
6277 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006278 * @ioc: Pointer to an adapter structure
6279 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006280 * action, page address, direction, physical address
6281 * and pointer to a configuration page header
6282 * Page header is updated.
6283 *
6284 * Returns 0 for success
6285 * -EPERM if not allowed due to ISR context
6286 * -EAGAIN if no msg frames currently available
6287 * -EFAULT for non-successful reply or no reply (timeout)
6288 */
6289int
6290mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6291{
6292 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306293 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006294 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006295 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306296 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006297 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306298 long timeout;
6299 int ret;
6300 u8 page_type = 0, extend_page;
6301 unsigned long timeleft;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306302 unsigned long flags;
6303 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306304 u8 issue_hard_reset = 0;
6305 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006306
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006307 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006308 * to be in ISR context, because that is fatal!
6309 */
6310 in_isr = in_interrupt();
6311 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306312 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006313 ioc->name));
6314 return -EPERM;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306315 }
6316
6317 /* don't send a config page during diag reset */
6318 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6319 if (ioc->ioc_reset_in_progress) {
6320 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6321 "%s: busy with host reset\n", ioc->name, __func__));
6322 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6323 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006324 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306325 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006326
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306327 /* don't send if no chance of success */
6328 if (!ioc->active ||
6329 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6330 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6331 "%s: ioc not operational, %d, %xh\n",
6332 ioc->name, __func__, ioc->active,
6333 mpt_GetIocState(ioc, 0)));
6334 return -EFAULT;
6335 }
6336
6337 retry_config:
6338 mutex_lock(&ioc->mptbase_cmds.mutex);
6339 /* init the internal cmd struct */
6340 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6341 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6342
Linus Torvalds1da177e2005-04-16 15:20:36 -07006343 /* Get and Populate a free Frame
6344 */
6345 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306346 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6347 "mpt_config: no msg frames!\n", ioc->name));
6348 ret = -EAGAIN;
6349 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006350 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306351
Linus Torvalds1da177e2005-04-16 15:20:36 -07006352 pReq = (Config_t *)mf;
6353 pReq->Action = pCfg->action;
6354 pReq->Reserved = 0;
6355 pReq->ChainOffset = 0;
6356 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006357
6358 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006359 pReq->ExtPageLength = 0;
6360 pReq->ExtPageType = 0;
6361 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006362
Linus Torvalds1da177e2005-04-16 15:20:36 -07006363 for (ii=0; ii < 8; ii++)
6364 pReq->Reserved2[ii] = 0;
6365
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006366 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6367 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6368 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6369 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6370
6371 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6372 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6373 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6374 pReq->ExtPageType = pExtHdr->ExtPageType;
6375 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6376
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306377 /* Page Length must be treated as a reserved field for the
6378 * extended header.
6379 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006380 pReq->Header.PageLength = 0;
6381 }
6382
Linus Torvalds1da177e2005-04-16 15:20:36 -07006383 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6384
6385 /* Add a SGE to the config request.
6386 */
6387 if (pCfg->dir)
6388 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6389 else
6390 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6391
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306392 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6393 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006394 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306395 page_type = pReq->ExtPageType;
6396 extend_page = 1;
6397 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006398 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306399 page_type = pReq->Header.PageType;
6400 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006401 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006402
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306403 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6404 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6405 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6406
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306407 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306408 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006409 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306410 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6411 timeout);
6412 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6413 ret = -ETIME;
6414 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6415 "Failed Sending Config request type 0x%x, page 0x%x,"
6416 " action %d, status %xh, time left %ld\n\n",
6417 ioc->name, page_type, pReq->Header.PageNumber,
6418 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6419 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6420 goto out;
6421 if (!timeleft)
6422 issue_hard_reset = 1;
6423 goto out;
6424 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006425
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306426 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6427 ret = -1;
6428 goto out;
6429 }
6430 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6431 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6432 if (ret == MPI_IOCSTATUS_SUCCESS) {
6433 if (extend_page) {
6434 pCfg->cfghdr.ehdr->ExtPageLength =
6435 le16_to_cpu(pReply->ExtPageLength);
6436 pCfg->cfghdr.ehdr->ExtPageType =
6437 pReply->ExtPageType;
6438 }
6439 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6440 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6441 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6442 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006443
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006445
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306446 if (retry_count)
6447 printk(MYIOC_s_INFO_FMT "Retry completed "
6448 "ret=0x%x timeleft=%ld\n",
6449 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006450
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306451 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6452 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006453
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306454out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006455
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306456 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6457 mutex_unlock(&ioc->mptbase_cmds.mutex);
6458 if (issue_hard_reset) {
6459 issue_hard_reset = 0;
6460 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
6461 ioc->name, __func__);
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) {
6977 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6978 return -1;
6979 }
6980 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6981 /* Disable reply interrupts (also blocks FreeQ) */
6982 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
6983 ioc->active = 0;
6984 time_count = jiffies;
6985
6986 rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
6987
6988 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6989 if (MptResetHandlers[cb_idx])
6990 mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
6991 }
6992
6993 if (rc)
6994 goto out;
6995
6996 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
6997 if (ioc_state != MPI_IOC_STATE_READY)
6998 goto out;
6999
7000 for (ii = 0; ii < 5; ii++) {
7001 /* Get IOC facts! Allow 5 retries */
7002 rc = GetIocFacts(ioc, sleepFlag,
7003 MPT_HOSTEVENT_IOC_RECOVER);
7004 if (rc == 0)
7005 break;
7006 if (sleepFlag == CAN_SLEEP)
7007 msleep(100);
7008 else
7009 mdelay(100);
7010 }
7011 if (ii == 5)
7012 goto out;
7013
7014 rc = PrimeIocFifos(ioc);
7015 if (rc != 0)
7016 goto out;
7017
7018 rc = SendIocInit(ioc, sleepFlag);
7019 if (rc != 0)
7020 goto out;
7021
7022 rc = SendEventNotification(ioc, 1, sleepFlag);
7023 if (rc != 0)
7024 goto out;
7025
7026 if (ioc->hard_resets < -1)
7027 ioc->hard_resets++;
7028
7029 /*
7030 * At this point, we know soft reset succeeded.
7031 */
7032
7033 ioc->active = 1;
7034 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
7035
7036 out:
7037 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7038 ioc->ioc_reset_in_progress = 0;
7039 ioc->taskmgmt_quiesce_io = 0;
7040 ioc->taskmgmt_in_progress = 0;
7041 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7042
7043 if (ioc->active) { /* otherwise, hard reset coming */
7044 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7045 if (MptResetHandlers[cb_idx])
7046 mpt_signal_reset(cb_idx, ioc,
7047 MPT_IOC_POST_RESET);
7048 }
7049 }
7050
7051 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7052 "SoftResetHandler: completed (%d seconds): %s\n",
7053 ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,
7054 ((rc == 0) ? "SUCCESS" : "FAILED")));
7055
7056 return rc;
7057}
7058
7059/**
7060 * mpt_Soft_Hard_ResetHandler - Try less expensive reset
7061 * @ioc: Pointer to MPT_ADAPTER structure
7062 * @sleepFlag: Indicates if sleep or schedule must be called.
7063
7064 *
7065 * Returns 0 for SUCCESS or -1 if FAILED.
7066 * Try for softreset first, only if it fails go for expensive
7067 * HardReset.
7068 **/
7069int
7070mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag) {
7071 int ret = -1;
7072
7073 ret = mpt_SoftResetHandler(ioc, sleepFlag);
7074 if (ret == 0)
7075 return ret;
7076 ret = mpt_HardResetHandler(ioc, sleepFlag);
7077 return ret;
7078}
7079EXPORT_SYMBOL(mpt_Soft_Hard_ResetHandler);
7080
Linus Torvalds1da177e2005-04-16 15:20:36 -07007081/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7082/*
7083 * Reset Handling
7084 */
7085/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7086/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007087 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07007088 * @ioc: Pointer to MPT_ADAPTER structure
7089 * @sleepFlag: Indicates if sleep or schedule must be called.
7090 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007091 * Issues SCSI Task Management call based on input arg values.
7092 * If TaskMgmt fails, returns associated SCSI request.
7093 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07007094 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
7095 * or a non-interrupt thread. In the former, must not call schedule().
7096 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007097 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07007098 * FW reload/initialization failed.
7099 *
7100 * Returns 0 for SUCCESS or -1 if FAILED.
7101 */
7102int
7103mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
7104{
Kashyap, Desaid1306912009-08-05 12:53:51 +05307105 int rc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307106 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007107 unsigned long flags;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307108 unsigned long time_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007109
Prakash, Sathya436ace72007-07-24 15:42:08 +05307110 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007111#ifdef MFCNT
7112 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
7113 printk("MF count 0x%x !\n", ioc->mfcnt);
7114#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05307115 if (mpt_fwfault_debug)
7116 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007117
7118 /* Reset the adapter. Prevent more than 1 call to
7119 * mpt_do_ioc_recovery at any instant in time.
7120 */
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307121 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7122 if (ioc->ioc_reset_in_progress) {
7123 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007124 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007125 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307126 ioc->ioc_reset_in_progress = 1;
7127 if (ioc->alt_ioc)
7128 ioc->alt_ioc->ioc_reset_in_progress = 1;
7129 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007130
Linus Torvalds1da177e2005-04-16 15:20:36 -07007131
7132 /* The SCSI driver needs to adjust timeouts on all current
7133 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02007134 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007135 * For all other protocol drivers, this is a no-op.
7136 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05307137 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7138 if (MptResetHandlers[cb_idx]) {
7139 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
7140 if (ioc->alt_ioc)
7141 mpt_signal_reset(cb_idx, ioc->alt_ioc,
7142 MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007143 }
7144 }
7145
Kashyap, Desai2f187862009-05-29 16:52:37 +05307146 time_count = jiffies;
7147 rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
7148 if (rc != 0) {
7149 printk(KERN_WARNING MYNAM
7150 ": WARNING - (%d) Cannot recover %s\n", rc, ioc->name);
7151 } else {
7152 if (ioc->hard_resets < -1)
7153 ioc->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007154 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007155
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307156 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7157 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307158 ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307159 ioc->taskmgmt_in_progress = 0;
7160 if (ioc->alt_ioc) {
7161 ioc->alt_ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307162 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307163 ioc->alt_ioc->taskmgmt_in_progress = 0;
7164 }
7165 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007166
Kashyap, Desaid1306912009-08-05 12:53:51 +05307167 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7168 if (MptResetHandlers[cb_idx]) {
7169 mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
7170 if (ioc->alt_ioc)
7171 mpt_signal_reset(cb_idx,
7172 ioc->alt_ioc, MPT_IOC_POST_RESET);
7173 }
7174 }
7175
Kashyap, Desai2f187862009-05-29 16:52:37 +05307176 dtmprintk(ioc,
7177 printk(MYIOC_s_DEBUG_FMT
7178 "HardResetHandler: completed (%d seconds): %s\n", ioc->name,
7179 jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?
7180 "SUCCESS" : "FAILED")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007181
7182 return rc;
7183}
7184
Kashyap, Desai2f187862009-05-29 16:52:37 +05307185#ifdef CONFIG_FUSION_LOGGING
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007186static void
Kashyap, Desai2f187862009-05-29 16:52:37 +05307187mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007188{
Eric Moore509e5e52006-04-26 13:22:37 -06007189 char *ds = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307190 u32 evData0;
7191 int ii;
7192 u8 event;
7193 char *evStr = ioc->evStr;
7194
7195 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7196 evData0 = le32_to_cpu(pEventReply->Data[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007197
7198 switch(event) {
7199 case MPI_EVENT_NONE:
7200 ds = "None";
7201 break;
7202 case MPI_EVENT_LOG_DATA:
7203 ds = "Log Data";
7204 break;
7205 case MPI_EVENT_STATE_CHANGE:
7206 ds = "State Change";
7207 break;
7208 case MPI_EVENT_UNIT_ATTENTION:
7209 ds = "Unit Attention";
7210 break;
7211 case MPI_EVENT_IOC_BUS_RESET:
7212 ds = "IOC Bus Reset";
7213 break;
7214 case MPI_EVENT_EXT_BUS_RESET:
7215 ds = "External Bus Reset";
7216 break;
7217 case MPI_EVENT_RESCAN:
7218 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007219 break;
7220 case MPI_EVENT_LINK_STATUS_CHANGE:
7221 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
7222 ds = "Link Status(FAILURE) Change";
7223 else
7224 ds = "Link Status(ACTIVE) Change";
7225 break;
7226 case MPI_EVENT_LOOP_STATE_CHANGE:
7227 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
7228 ds = "Loop State(LIP) Change";
7229 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Kashyap, Desai2f187862009-05-29 16:52:37 +05307230 ds = "Loop State(LPE) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007231 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05307232 ds = "Loop State(LPB) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007233 break;
7234 case MPI_EVENT_LOGOUT:
7235 ds = "Logout";
7236 break;
7237 case MPI_EVENT_EVENT_CHANGE:
7238 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06007239 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007240 else
Eric Moore4f766dc2006-07-11 17:24:07 -06007241 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007242 break;
7243 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007244 {
7245 u8 ReasonCode = (u8)(evData0 >> 16);
7246 switch (ReasonCode) {
7247 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
7248 ds = "Integrated Raid: Volume Created";
7249 break;
7250 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
7251 ds = "Integrated Raid: Volume Deleted";
7252 break;
7253 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
7254 ds = "Integrated Raid: Volume Settings Changed";
7255 break;
7256 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
7257 ds = "Integrated Raid: Volume Status Changed";
7258 break;
7259 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
7260 ds = "Integrated Raid: Volume Physdisk Changed";
7261 break;
7262 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
7263 ds = "Integrated Raid: Physdisk Created";
7264 break;
7265 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
7266 ds = "Integrated Raid: Physdisk Deleted";
7267 break;
7268 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
7269 ds = "Integrated Raid: Physdisk Settings Changed";
7270 break;
7271 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
7272 ds = "Integrated Raid: Physdisk Status Changed";
7273 break;
7274 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
7275 ds = "Integrated Raid: Domain Validation Needed";
7276 break;
7277 case MPI_EVENT_RAID_RC_SMART_DATA :
7278 ds = "Integrated Raid; Smart Data";
7279 break;
7280 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
7281 ds = "Integrated Raid: Replace Action Started";
7282 break;
7283 default:
7284 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007285 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007286 }
7287 break;
7288 }
7289 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
7290 ds = "SCSI Device Status Change";
7291 break;
7292 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
7293 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007294 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007295 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007296 u8 ReasonCode = (u8)(evData0 >> 16);
7297 switch (ReasonCode) {
7298 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007299 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007300 "SAS Device Status Change: Added: "
7301 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007302 break;
7303 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06007304 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007305 "SAS Device Status Change: Deleted: "
7306 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007307 break;
7308 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06007309 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007310 "SAS Device Status Change: SMART Data: "
7311 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007312 break;
7313 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007314 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007315 "SAS Device Status Change: No Persistancy: "
7316 "id=%d channel=%d", id, channel);
7317 break;
7318 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
7319 snprintf(evStr, EVENT_DESCR_STR_SZ,
7320 "SAS Device Status Change: Unsupported Device "
7321 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007322 break;
7323 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
7324 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007325 "SAS Device Status Change: Internal Device "
7326 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007327 break;
7328 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
7329 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007330 "SAS Device Status Change: Internal Task "
7331 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007332 break;
7333 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
7334 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007335 "SAS Device Status Change: Internal Abort "
7336 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007337 break;
7338 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
7339 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007340 "SAS Device Status Change: Internal Clear "
7341 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007342 break;
7343 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
7344 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007345 "SAS Device Status Change: Internal Query "
7346 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007347 break;
7348 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007349 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007350 "SAS Device Status Change: Unknown: "
7351 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06007352 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007353 }
7354 break;
7355 }
7356 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
7357 ds = "Bus Timer Expired";
7358 break;
7359 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07007360 {
7361 u16 curr_depth = (u16)(evData0 >> 16);
7362 u8 channel = (u8)(evData0 >> 8);
7363 u8 id = (u8)(evData0);
7364
7365 snprintf(evStr, EVENT_DESCR_STR_SZ,
7366 "Queue Full: channel=%d id=%d depth=%d",
7367 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007368 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07007369 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007370 case MPI_EVENT_SAS_SES:
7371 ds = "SAS SES Event";
7372 break;
7373 case MPI_EVENT_PERSISTENT_TABLE_FULL:
7374 ds = "Persistent Table Full";
7375 break;
7376 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07007377 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007378 u8 LinkRates = (u8)(evData0 >> 8);
7379 u8 PhyNumber = (u8)(evData0);
7380 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
7381 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
7382 switch (LinkRates) {
7383 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06007384 snprintf(evStr, EVENT_DESCR_STR_SZ,
7385 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007386 " Rate Unknown",PhyNumber);
7387 break;
7388 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06007389 snprintf(evStr, EVENT_DESCR_STR_SZ,
7390 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007391 " Phy Disabled",PhyNumber);
7392 break;
7393 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06007394 snprintf(evStr, EVENT_DESCR_STR_SZ,
7395 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007396 " Failed Speed Nego",PhyNumber);
7397 break;
7398 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06007399 snprintf(evStr, EVENT_DESCR_STR_SZ,
7400 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007401 " Sata OOB Completed",PhyNumber);
7402 break;
7403 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06007404 snprintf(evStr, EVENT_DESCR_STR_SZ,
7405 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007406 " Rate 1.5 Gbps",PhyNumber);
7407 break;
7408 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06007409 snprintf(evStr, EVENT_DESCR_STR_SZ,
7410 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007411 " Rate 3.0 Gpbs",PhyNumber);
7412 break;
7413 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007414 snprintf(evStr, EVENT_DESCR_STR_SZ,
7415 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007416 break;
7417 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007418 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007419 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007420 case MPI_EVENT_SAS_DISCOVERY_ERROR:
7421 ds = "SAS Discovery Error";
7422 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007423 case MPI_EVENT_IR_RESYNC_UPDATE:
7424 {
7425 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06007426 snprintf(evStr, EVENT_DESCR_STR_SZ,
7427 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07007428 break;
7429 }
7430 case MPI_EVENT_IR2:
7431 {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307432 u8 id = (u8)(evData0);
7433 u8 channel = (u8)(evData0 >> 8);
7434 u8 phys_num = (u8)(evData0 >> 24);
Moore, Eric3a892be2006-03-14 09:14:03 -07007435 u8 ReasonCode = (u8)(evData0 >> 16);
Kashyap, Desai2f187862009-05-29 16:52:37 +05307436
Moore, Eric3a892be2006-03-14 09:14:03 -07007437 switch (ReasonCode) {
7438 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307439 snprintf(evStr, EVENT_DESCR_STR_SZ,
7440 "IR2: LD State Changed: "
7441 "id=%d channel=%d phys_num=%d",
7442 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007443 break;
7444 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307445 snprintf(evStr, EVENT_DESCR_STR_SZ,
7446 "IR2: PD State Changed "
7447 "id=%d channel=%d phys_num=%d",
7448 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007449 break;
7450 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307451 snprintf(evStr, EVENT_DESCR_STR_SZ,
7452 "IR2: Bad Block Table Full: "
7453 "id=%d channel=%d phys_num=%d",
7454 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007455 break;
7456 case MPI_EVENT_IR2_RC_PD_INSERTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307457 snprintf(evStr, EVENT_DESCR_STR_SZ,
7458 "IR2: PD Inserted: "
7459 "id=%d channel=%d phys_num=%d",
7460 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007461 break;
7462 case MPI_EVENT_IR2_RC_PD_REMOVED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307463 snprintf(evStr, EVENT_DESCR_STR_SZ,
7464 "IR2: PD Removed: "
7465 "id=%d channel=%d phys_num=%d",
7466 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007467 break;
7468 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307469 snprintf(evStr, EVENT_DESCR_STR_SZ,
7470 "IR2: Foreign CFG Detected: "
7471 "id=%d channel=%d phys_num=%d",
7472 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007473 break;
7474 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307475 snprintf(evStr, EVENT_DESCR_STR_SZ,
7476 "IR2: Rebuild Medium Error: "
7477 "id=%d channel=%d phys_num=%d",
7478 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007479 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05307480 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
7481 snprintf(evStr, EVENT_DESCR_STR_SZ,
7482 "IR2: Dual Port Added: "
7483 "id=%d channel=%d phys_num=%d",
7484 id, channel, phys_num);
7485 break;
7486 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
7487 snprintf(evStr, EVENT_DESCR_STR_SZ,
7488 "IR2: Dual Port Removed: "
7489 "id=%d channel=%d phys_num=%d",
7490 id, channel, phys_num);
7491 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007492 default:
7493 ds = "IR2";
7494 break;
7495 }
7496 break;
7497 }
7498 case MPI_EVENT_SAS_DISCOVERY:
7499 {
7500 if (evData0)
7501 ds = "SAS Discovery: Start";
7502 else
7503 ds = "SAS Discovery: Stop";
7504 break;
7505 }
7506 case MPI_EVENT_LOG_ENTRY_ADDED:
7507 ds = "SAS Log Entry Added";
7508 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007509
Eric Moorec6c727a2007-01-29 09:44:54 -07007510 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
7511 {
7512 u8 phy_num = (u8)(evData0);
7513 u8 port_num = (u8)(evData0 >> 8);
7514 u8 port_width = (u8)(evData0 >> 16);
7515 u8 primative = (u8)(evData0 >> 24);
7516 snprintf(evStr, EVENT_DESCR_STR_SZ,
7517 "SAS Broadcase Primative: phy=%d port=%d "
7518 "width=%d primative=0x%02x",
7519 phy_num, port_num, port_width, primative);
7520 break;
7521 }
7522
7523 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7524 {
7525 u8 reason = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007526
Kashyap, Desai2f187862009-05-29 16:52:37 +05307527 switch (reason) {
7528 case MPI_EVENT_SAS_INIT_RC_ADDED:
7529 ds = "SAS Initiator Status Change: Added";
7530 break;
7531 case MPI_EVENT_SAS_INIT_RC_REMOVED:
7532 ds = "SAS Initiator Status Change: Deleted";
7533 break;
7534 default:
7535 ds = "SAS Initiator Status Change";
7536 break;
7537 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007538 break;
7539 }
7540
7541 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7542 {
7543 u8 max_init = (u8)(evData0);
7544 u8 current_init = (u8)(evData0 >> 8);
7545
7546 snprintf(evStr, EVENT_DESCR_STR_SZ,
7547 "SAS Initiator Device Table Overflow: max initiators=%02d "
7548 "current initators=%02d",
7549 max_init, current_init);
7550 break;
7551 }
7552 case MPI_EVENT_SAS_SMP_ERROR:
7553 {
7554 u8 status = (u8)(evData0);
7555 u8 port_num = (u8)(evData0 >> 8);
7556 u8 result = (u8)(evData0 >> 16);
7557
7558 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7559 snprintf(evStr, EVENT_DESCR_STR_SZ,
7560 "SAS SMP Error: port=%d result=0x%02x",
7561 port_num, result);
7562 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7563 snprintf(evStr, EVENT_DESCR_STR_SZ,
7564 "SAS SMP Error: port=%d : CRC Error",
7565 port_num);
7566 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7567 snprintf(evStr, EVENT_DESCR_STR_SZ,
7568 "SAS SMP Error: port=%d : Timeout",
7569 port_num);
7570 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7571 snprintf(evStr, EVENT_DESCR_STR_SZ,
7572 "SAS SMP Error: port=%d : No Destination",
7573 port_num);
7574 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7575 snprintf(evStr, EVENT_DESCR_STR_SZ,
7576 "SAS SMP Error: port=%d : Bad Destination",
7577 port_num);
7578 else
7579 snprintf(evStr, EVENT_DESCR_STR_SZ,
7580 "SAS SMP Error: port=%d : status=0x%02x",
7581 port_num, status);
7582 break;
7583 }
7584
Kashyap, Desai2f187862009-05-29 16:52:37 +05307585 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
7586 {
7587 u8 reason = (u8)(evData0);
7588
7589 switch (reason) {
7590 case MPI_EVENT_SAS_EXP_RC_ADDED:
7591 ds = "Expander Status Change: Added";
7592 break;
7593 case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
7594 ds = "Expander Status Change: Deleted";
7595 break;
7596 default:
7597 ds = "Expander Status Change";
7598 break;
7599 }
7600 break;
7601 }
7602
Linus Torvalds1da177e2005-04-16 15:20:36 -07007603 /*
7604 * MPT base "custom" events may be added here...
7605 */
7606 default:
7607 ds = "Unknown";
7608 break;
7609 }
Eric Moore509e5e52006-04-26 13:22:37 -06007610 if (ds)
7611 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007612
Kashyap, Desai2f187862009-05-29 16:52:37 +05307613
7614 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7615 "MPT event:(%02Xh) : %s\n",
7616 ioc->name, event, evStr));
7617
7618 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
7619 ": Event data:\n"));
7620 for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
7621 devtverboseprintk(ioc, printk(" %08x",
7622 le32_to_cpu(pEventReply->Data[ii])));
7623 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
7624}
7625#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007626/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007627/**
7628 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007629 * @ioc: Pointer to MPT_ADAPTER structure
7630 * @pEventReply: Pointer to EventNotification reply frame
7631 * @evHandlers: Pointer to integer, number of event handlers
7632 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007633 * Routes a received EventNotificationReply to all currently registered
7634 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007635 * Returns sum of event handlers return values.
7636 */
7637static int
7638ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7639{
7640 u16 evDataLen;
7641 u32 evData0 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007642 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307643 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007644 int r = 0;
7645 int handlers = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007646 u8 event;
7647
7648 /*
7649 * Do platform normalization of values
7650 */
7651 event = le32_to_cpu(pEventReply->Event) & 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007652 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7653 if (evDataLen) {
7654 evData0 = le32_to_cpu(pEventReply->Data[0]);
7655 }
7656
Prakash, Sathya436ace72007-07-24 15:42:08 +05307657#ifdef CONFIG_FUSION_LOGGING
Kashyap, Desai2f187862009-05-29 16:52:37 +05307658 if (evDataLen)
7659 mpt_display_event_info(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007660#endif
7661
7662 /*
7663 * Do general / base driver event processing
7664 */
7665 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007666 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7667 if (evDataLen) {
7668 u8 evState = evData0 & 0xFF;
7669
7670 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7671
7672 /* Update EventState field in cached IocFacts */
7673 if (ioc->facts.Function) {
7674 ioc->facts.EventState = evState;
7675 }
7676 }
7677 break;
Moore, Ericece50912006-01-16 18:53:19 -07007678 case MPI_EVENT_INTEGRATED_RAID:
7679 mptbase_raid_process_event_data(ioc,
7680 (MpiEventDataRaid_t *)pEventReply->Data);
7681 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007682 default:
7683 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007684 }
7685
7686 /*
7687 * Should this event be logged? Events are written sequentially.
7688 * When buffer is full, start again at the top.
7689 */
7690 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7691 int idx;
7692
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007693 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007694
7695 ioc->events[idx].event = event;
7696 ioc->events[idx].eventContext = ioc->eventContext;
7697
7698 for (ii = 0; ii < 2; ii++) {
7699 if (ii < evDataLen)
7700 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7701 else
7702 ioc->events[idx].data[ii] = 0;
7703 }
7704
7705 ioc->eventContext++;
7706 }
7707
7708
7709 /*
7710 * Call each currently registered protocol event handler.
7711 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007712 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307713 if (MptEvHandlers[cb_idx]) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307714 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7715 "Routing Event to event handler #%d\n",
7716 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307717 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007718 handlers++;
7719 }
7720 }
7721 /* FIXME? Examine results here? */
7722
7723 /*
7724 * If needed, send (a single) EventAck.
7725 */
7726 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307727 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007728 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007729 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307730 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007731 ioc->name, ii));
7732 }
7733 }
7734
7735 *evHandlers = handlers;
7736 return r;
7737}
7738
7739/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007740/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007741 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7742 * @ioc: Pointer to MPT_ADAPTER structure
7743 * @log_info: U32 LogInfo reply word from the IOC
7744 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007745 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007746 */
7747static void
7748mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7749{
Eric Moore7c431e52007-06-13 16:34:36 -06007750 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007751
Eric Moore7c431e52007-06-13 16:34:36 -06007752 switch (log_info & 0xFF000000) {
7753 case MPI_IOCLOGINFO_FC_INIT_BASE:
7754 desc = "FCP Initiator";
7755 break;
7756 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7757 desc = "FCP Target";
7758 break;
7759 case MPI_IOCLOGINFO_FC_LAN_BASE:
7760 desc = "LAN";
7761 break;
7762 case MPI_IOCLOGINFO_FC_MSG_BASE:
7763 desc = "MPI Message Layer";
7764 break;
7765 case MPI_IOCLOGINFO_FC_LINK_BASE:
7766 desc = "FC Link";
7767 break;
7768 case MPI_IOCLOGINFO_FC_CTX_BASE:
7769 desc = "Context Manager";
7770 break;
7771 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7772 desc = "Invalid Field Offset";
7773 break;
7774 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7775 desc = "State Change Info";
7776 break;
7777 }
7778
7779 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7780 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007781}
7782
7783/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007784/**
Moore, Eric335a9412006-01-17 17:06:23 -07007785 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007786 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007787 * @log_info: U32 LogInfo word from the IOC
7788 *
7789 * Refer to lsi/sp_log.h.
7790 */
7791static void
Moore, Eric335a9412006-01-17 17:06:23 -07007792mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007793{
7794 u32 info = log_info & 0x00FF0000;
7795 char *desc = "unknown";
7796
7797 switch (info) {
7798 case 0x00010000:
7799 desc = "bug! MID not found";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007800 break;
7801
7802 case 0x00020000:
7803 desc = "Parity Error";
7804 break;
7805
7806 case 0x00030000:
7807 desc = "ASYNC Outbound Overrun";
7808 break;
7809
7810 case 0x00040000:
7811 desc = "SYNC Offset Error";
7812 break;
7813
7814 case 0x00050000:
7815 desc = "BM Change";
7816 break;
7817
7818 case 0x00060000:
7819 desc = "Msg In Overflow";
7820 break;
7821
7822 case 0x00070000:
7823 desc = "DMA Error";
7824 break;
7825
7826 case 0x00080000:
7827 desc = "Outbound DMA Overrun";
7828 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007829
Linus Torvalds1da177e2005-04-16 15:20:36 -07007830 case 0x00090000:
7831 desc = "Task Management";
7832 break;
7833
7834 case 0x000A0000:
7835 desc = "Device Problem";
7836 break;
7837
7838 case 0x000B0000:
7839 desc = "Invalid Phase Change";
7840 break;
7841
7842 case 0x000C0000:
7843 desc = "Untagged Table Size";
7844 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007845
Linus Torvalds1da177e2005-04-16 15:20:36 -07007846 }
7847
7848 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7849}
7850
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007851/* strings for sas loginfo */
7852 static char *originator_str[] = {
7853 "IOP", /* 00h */
7854 "PL", /* 01h */
7855 "IR" /* 02h */
7856 };
7857 static char *iop_code_str[] = {
7858 NULL, /* 00h */
7859 "Invalid SAS Address", /* 01h */
7860 NULL, /* 02h */
7861 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007862 "Diag Message Error", /* 04h */
7863 "Task Terminated", /* 05h */
7864 "Enclosure Management", /* 06h */
7865 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007866 };
7867 static char *pl_code_str[] = {
7868 NULL, /* 00h */
7869 "Open Failure", /* 01h */
7870 "Invalid Scatter Gather List", /* 02h */
7871 "Wrong Relative Offset or Frame Length", /* 03h */
7872 "Frame Transfer Error", /* 04h */
7873 "Transmit Frame Connected Low", /* 05h */
7874 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7875 "SATA Read Log Receive Data Error", /* 07h */
7876 "SATA NCQ Fail All Commands After Error", /* 08h */
7877 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7878 "Receive Frame Invalid Message", /* 0Ah */
7879 "Receive Context Message Valid Error", /* 0Bh */
7880 "Receive Frame Current Frame Error", /* 0Ch */
7881 "SATA Link Down", /* 0Dh */
7882 "Discovery SATA Init W IOS", /* 0Eh */
7883 "Config Invalid Page", /* 0Fh */
7884 "Discovery SATA Init Timeout", /* 10h */
7885 "Reset", /* 11h */
7886 "Abort", /* 12h */
7887 "IO Not Yet Executed", /* 13h */
7888 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007889 "Persistent Reservation Out Not Affiliation "
7890 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007891 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007892 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007893 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007894 NULL, /* 19h */
7895 NULL, /* 1Ah */
7896 NULL, /* 1Bh */
7897 NULL, /* 1Ch */
7898 NULL, /* 1Dh */
7899 NULL, /* 1Eh */
7900 NULL, /* 1Fh */
7901 "Enclosure Management" /* 20h */
7902 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007903 static char *ir_code_str[] = {
7904 "Raid Action Error", /* 00h */
7905 NULL, /* 00h */
7906 NULL, /* 01h */
7907 NULL, /* 02h */
7908 NULL, /* 03h */
7909 NULL, /* 04h */
7910 NULL, /* 05h */
7911 NULL, /* 06h */
7912 NULL /* 07h */
7913 };
7914 static char *raid_sub_code_str[] = {
7915 NULL, /* 00h */
7916 "Volume Creation Failed: Data Passed too "
7917 "Large", /* 01h */
7918 "Volume Creation Failed: Duplicate Volumes "
7919 "Attempted", /* 02h */
7920 "Volume Creation Failed: Max Number "
7921 "Supported Volumes Exceeded", /* 03h */
7922 "Volume Creation Failed: DMA Error", /* 04h */
7923 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7924 "Volume Creation Failed: Error Reading "
7925 "MFG Page 4", /* 06h */
7926 "Volume Creation Failed: Creating Internal "
7927 "Structures", /* 07h */
7928 NULL, /* 08h */
7929 NULL, /* 09h */
7930 NULL, /* 0Ah */
7931 NULL, /* 0Bh */
7932 NULL, /* 0Ch */
7933 NULL, /* 0Dh */
7934 NULL, /* 0Eh */
7935 NULL, /* 0Fh */
7936 "Activation failed: Already Active Volume", /* 10h */
7937 "Activation failed: Unsupported Volume Type", /* 11h */
7938 "Activation failed: Too Many Active Volumes", /* 12h */
7939 "Activation failed: Volume ID in Use", /* 13h */
7940 "Activation failed: Reported Failure", /* 14h */
7941 "Activation failed: Importing a Volume", /* 15h */
7942 NULL, /* 16h */
7943 NULL, /* 17h */
7944 NULL, /* 18h */
7945 NULL, /* 19h */
7946 NULL, /* 1Ah */
7947 NULL, /* 1Bh */
7948 NULL, /* 1Ch */
7949 NULL, /* 1Dh */
7950 NULL, /* 1Eh */
7951 NULL, /* 1Fh */
7952 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7953 "Phys Disk failed: Data Passed too Large", /* 21h */
7954 "Phys Disk failed: DMA Error", /* 22h */
7955 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7956 "Phys Disk failed: Creating Phys Disk Config "
7957 "Page", /* 24h */
7958 NULL, /* 25h */
7959 NULL, /* 26h */
7960 NULL, /* 27h */
7961 NULL, /* 28h */
7962 NULL, /* 29h */
7963 NULL, /* 2Ah */
7964 NULL, /* 2Bh */
7965 NULL, /* 2Ch */
7966 NULL, /* 2Dh */
7967 NULL, /* 2Eh */
7968 NULL, /* 2Fh */
7969 "Compatibility Error: IR Disabled", /* 30h */
7970 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7971 "Compatibility Error: Device not Direct Access "
7972 "Device ", /* 32h */
7973 "Compatibility Error: Removable Device Found", /* 33h */
7974 "Compatibility Error: Device SCSI Version not "
7975 "2 or Higher", /* 34h */
7976 "Compatibility Error: SATA Device, 48 BIT LBA "
7977 "not Supported", /* 35h */
7978 "Compatibility Error: Device doesn't have "
7979 "512 Byte Block Sizes", /* 36h */
7980 "Compatibility Error: Volume Type Check Failed", /* 37h */
7981 "Compatibility Error: Volume Type is "
7982 "Unsupported by FW", /* 38h */
7983 "Compatibility Error: Disk Drive too Small for "
7984 "use in Volume", /* 39h */
7985 "Compatibility Error: Phys Disk for Create "
7986 "Volume not Found", /* 3Ah */
7987 "Compatibility Error: Too Many or too Few "
7988 "Disks for Volume Type", /* 3Bh */
7989 "Compatibility Error: Disk stripe Sizes "
7990 "Must be 64KB", /* 3Ch */
7991 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7992 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007993
7994/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007995/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007996 * mpt_sas_log_info - Log information returned from SAS IOC.
7997 * @ioc: Pointer to MPT_ADAPTER structure
7998 * @log_info: U32 LogInfo reply word from the IOC
7999 *
8000 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008001 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008002static void
8003mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
8004{
8005union loginfo_type {
8006 u32 loginfo;
8007 struct {
8008 u32 subcode:16;
8009 u32 code:8;
8010 u32 originator:4;
8011 u32 bus_type:4;
8012 }dw;
8013};
8014 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07008015 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008016 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07008017 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008018
8019 sas_loginfo.loginfo = log_info;
8020 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008021 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008022 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07008023
8024 originator_desc = originator_str[sas_loginfo.dw.originator];
8025
8026 switch (sas_loginfo.dw.originator) {
8027
8028 case 0: /* IOP */
8029 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008030 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008031 code_desc = iop_code_str[sas_loginfo.dw.code];
8032 break;
8033 case 1: /* PL */
8034 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008035 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008036 code_desc = pl_code_str[sas_loginfo.dw.code];
8037 break;
8038 case 2: /* IR */
8039 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008040 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008041 break;
8042 code_desc = ir_code_str[sas_loginfo.dw.code];
8043 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008044 ARRAY_SIZE(raid_sub_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008045 break;
8046 if (sas_loginfo.dw.code == 0)
8047 sub_code_desc =
8048 raid_sub_code_str[sas_loginfo.dw.subcode];
8049 break;
8050 default:
8051 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008052 }
8053
Eric Moorec6c727a2007-01-29 09:44:54 -07008054 if (sub_code_desc != NULL)
8055 printk(MYIOC_s_INFO_FMT
8056 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
8057 " SubCode={%s}\n",
8058 ioc->name, log_info, originator_desc, code_desc,
8059 sub_code_desc);
8060 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008061 printk(MYIOC_s_INFO_FMT
8062 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
8063 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008064 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008065 sas_loginfo.dw.subcode);
8066 else
8067 printk(MYIOC_s_INFO_FMT
8068 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
8069 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008070 ioc->name, log_info, originator_desc,
8071 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008072}
8073
Linus Torvalds1da177e2005-04-16 15:20:36 -07008074/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008075/**
Eric Moorec6c727a2007-01-29 09:44:54 -07008076 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
8077 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08008078 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07008079 * @mf: Pointer to MPT request frame
8080 *
8081 * Refer to lsi/mpi.h.
8082 **/
8083static void
8084mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
8085{
8086 Config_t *pReq = (Config_t *)mf;
8087 char extend_desc[EVENT_DESCR_STR_SZ];
8088 char *desc = NULL;
8089 u32 form;
8090 u8 page_type;
8091
8092 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
8093 page_type = pReq->ExtPageType;
8094 else
8095 page_type = pReq->Header.PageType;
8096
8097 /*
8098 * ignore invalid page messages for GET_NEXT_HANDLE
8099 */
8100 form = le32_to_cpu(pReq->PageAddress);
8101 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
8102 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
8103 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
8104 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
8105 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
8106 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
8107 return;
8108 }
8109 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
8110 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
8111 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
8112 return;
8113 }
8114
8115 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
8116 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
8117 page_type, pReq->Header.PageNumber, pReq->Action, form);
8118
8119 switch (ioc_status) {
8120
8121 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8122 desc = "Config Page Invalid Action";
8123 break;
8124
8125 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8126 desc = "Config Page Invalid Type";
8127 break;
8128
8129 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8130 desc = "Config Page Invalid Page";
8131 break;
8132
8133 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8134 desc = "Config Page Invalid Data";
8135 break;
8136
8137 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8138 desc = "Config Page No Defaults";
8139 break;
8140
8141 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
8142 desc = "Config Page Can't Commit";
8143 break;
8144 }
8145
8146 if (!desc)
8147 return;
8148
Eric Moore29dd3602007-09-14 18:46:51 -06008149 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
8150 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07008151}
8152
8153/**
8154 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07008155 * @ioc: Pointer to MPT_ADAPTER structure
8156 * @ioc_status: U32 IOCStatus word from IOC
8157 * @mf: Pointer to MPT request frame
8158 *
8159 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008160 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07008161static void
Eric Moorec6c727a2007-01-29 09:44:54 -07008162mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008163{
8164 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06008165 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008166
8167 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07008168
8169/****************************************************************************/
8170/* Common IOCStatus values for all replies */
8171/****************************************************************************/
8172
Linus Torvalds1da177e2005-04-16 15:20:36 -07008173 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
8174 desc = "Invalid Function";
8175 break;
8176
8177 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
8178 desc = "Busy";
8179 break;
8180
8181 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
8182 desc = "Invalid SGL";
8183 break;
8184
8185 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
8186 desc = "Internal Error";
8187 break;
8188
8189 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
8190 desc = "Reserved";
8191 break;
8192
8193 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
8194 desc = "Insufficient Resources";
8195 break;
8196
8197 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
8198 desc = "Invalid Field";
8199 break;
8200
8201 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
8202 desc = "Invalid State";
8203 break;
8204
Eric Moorec6c727a2007-01-29 09:44:54 -07008205/****************************************************************************/
8206/* Config IOCStatus values */
8207/****************************************************************************/
8208
Linus Torvalds1da177e2005-04-16 15:20:36 -07008209 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8210 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8211 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8212 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8213 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8214 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008215 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008216 break;
8217
Eric Moorec6c727a2007-01-29 09:44:54 -07008218/****************************************************************************/
8219/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
8220/* */
8221/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
8222/* */
8223/****************************************************************************/
8224
Linus Torvalds1da177e2005-04-16 15:20:36 -07008225 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008226 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008227 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
8228 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
8229 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
8230 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008231 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008232 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008233 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008234 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008235 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008236 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07008237 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008238 break;
8239
Eric Moorec6c727a2007-01-29 09:44:54 -07008240/****************************************************************************/
8241/* SCSI Target values */
8242/****************************************************************************/
8243
8244 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
8245 desc = "Target: Priority IO";
8246 break;
8247
8248 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
8249 desc = "Target: Invalid Port";
8250 break;
8251
8252 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
8253 desc = "Target Invalid IO Index:";
8254 break;
8255
8256 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
8257 desc = "Target: Aborted";
8258 break;
8259
8260 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
8261 desc = "Target: No Conn Retryable";
8262 break;
8263
8264 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
8265 desc = "Target: No Connection";
8266 break;
8267
8268 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
8269 desc = "Target: Transfer Count Mismatch";
8270 break;
8271
8272 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
8273 desc = "Target: STS Data not Sent";
8274 break;
8275
8276 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
8277 desc = "Target: Data Offset Error";
8278 break;
8279
8280 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
8281 desc = "Target: Too Much Write Data";
8282 break;
8283
8284 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
8285 desc = "Target: IU Too Short";
8286 break;
8287
8288 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
8289 desc = "Target: ACK NAK Timeout";
8290 break;
8291
8292 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
8293 desc = "Target: Nak Received";
8294 break;
8295
8296/****************************************************************************/
8297/* Fibre Channel Direct Access values */
8298/****************************************************************************/
8299
8300 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
8301 desc = "FC: Aborted";
8302 break;
8303
8304 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
8305 desc = "FC: RX ID Invalid";
8306 break;
8307
8308 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
8309 desc = "FC: DID Invalid";
8310 break;
8311
8312 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
8313 desc = "FC: Node Logged Out";
8314 break;
8315
8316 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
8317 desc = "FC: Exchange Canceled";
8318 break;
8319
8320/****************************************************************************/
8321/* LAN values */
8322/****************************************************************************/
8323
8324 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
8325 desc = "LAN: Device not Found";
8326 break;
8327
8328 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
8329 desc = "LAN: Device Failure";
8330 break;
8331
8332 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
8333 desc = "LAN: Transmit Error";
8334 break;
8335
8336 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
8337 desc = "LAN: Transmit Aborted";
8338 break;
8339
8340 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
8341 desc = "LAN: Receive Error";
8342 break;
8343
8344 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
8345 desc = "LAN: Receive Aborted";
8346 break;
8347
8348 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
8349 desc = "LAN: Partial Packet";
8350 break;
8351
8352 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
8353 desc = "LAN: Canceled";
8354 break;
8355
8356/****************************************************************************/
8357/* Serial Attached SCSI values */
8358/****************************************************************************/
8359
8360 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
8361 desc = "SAS: SMP Request Failed";
8362 break;
8363
8364 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
8365 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07008366 break;
8367
8368 default:
8369 desc = "Others";
8370 break;
8371 }
Eric Moorec6c727a2007-01-29 09:44:54 -07008372
8373 if (!desc)
8374 return;
8375
Eric Moore29dd3602007-09-14 18:46:51 -06008376 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
8377 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008378}
8379
8380/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008381EXPORT_SYMBOL(mpt_attach);
8382EXPORT_SYMBOL(mpt_detach);
8383#ifdef CONFIG_PM
8384EXPORT_SYMBOL(mpt_resume);
8385EXPORT_SYMBOL(mpt_suspend);
8386#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07008387EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008388EXPORT_SYMBOL(mpt_register);
8389EXPORT_SYMBOL(mpt_deregister);
8390EXPORT_SYMBOL(mpt_event_register);
8391EXPORT_SYMBOL(mpt_event_deregister);
8392EXPORT_SYMBOL(mpt_reset_register);
8393EXPORT_SYMBOL(mpt_reset_deregister);
8394EXPORT_SYMBOL(mpt_device_driver_register);
8395EXPORT_SYMBOL(mpt_device_driver_deregister);
8396EXPORT_SYMBOL(mpt_get_msg_frame);
8397EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05308398EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008399EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008400EXPORT_SYMBOL(mpt_send_handshake_request);
8401EXPORT_SYMBOL(mpt_verify_adapter);
8402EXPORT_SYMBOL(mpt_GetIocState);
8403EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008404EXPORT_SYMBOL(mpt_HardResetHandler);
8405EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008406EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008407EXPORT_SYMBOL(mpt_alloc_fw_memory);
8408EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02008409EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07008410EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008411
Linus Torvalds1da177e2005-04-16 15:20:36 -07008412/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008413/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008414 * fusion_init - Fusion MPT base driver initialization routine.
8415 *
8416 * Returns 0 for success, non-zero for failure.
8417 */
8418static int __init
8419fusion_init(void)
8420{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308421 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008422
8423 show_mptmod_ver(my_NAME, my_VERSION);
8424 printk(KERN_INFO COPYRIGHT "\n");
8425
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308426 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
8427 MptCallbacks[cb_idx] = NULL;
8428 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
8429 MptEvHandlers[cb_idx] = NULL;
8430 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008431 }
8432
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008433 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07008434 * EventNotification handling.
8435 */
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05308436 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008437
8438 /* Register for hard reset handling callbacks.
8439 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05308440 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008441
8442#ifdef CONFIG_PROC_FS
8443 (void) procmpt_create();
8444#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008445 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008446}
8447
8448/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008449/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008450 * fusion_exit - Perform driver unload cleanup.
8451 *
8452 * This routine frees all resources associated with each MPT adapter
8453 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
8454 */
8455static void __exit
8456fusion_exit(void)
8457{
8458
Linus Torvalds1da177e2005-04-16 15:20:36 -07008459 mpt_reset_deregister(mpt_base_index);
8460
8461#ifdef CONFIG_PROC_FS
8462 procmpt_destroy();
8463#endif
8464}
8465
Linus Torvalds1da177e2005-04-16 15:20:36 -07008466module_init(fusion_init);
8467module_exit(fusion_exit);