blob: d8c668d64418c9e453675b82c56388813258629e [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);
Rusty Russell57ba4712010-08-11 23:04:39 -0600112module_param(mpt_fwfault_debug, int, 0600);
Kashyap, Desai2f4c7822009-01-06 15:03:37 +0530113MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault"
114 " and halt Firmware on fault - (default=0)");
115
116
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530117static char MptCallbacksName[MPT_MAX_PROTOCOL_DRIVERS][50];
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);
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530216static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info , u8 cb_idx);
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)
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530493 mpt_sas_log_info(ioc, log_info, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600494 }
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
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530647mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass, char *func_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648{
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;
Kashyap, Desai213aaca2010-07-26 18:57:36 +0530662 memcpy(MptCallbacksName[cb_idx], func_name,
663 strlen(func_name) > 50 ? 50 : strlen(func_name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 break;
665 }
666 }
667
668 return last_drv_idx;
669}
670
671/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
672/**
673 * mpt_deregister - Deregister a protocol drivers resources.
674 * @cb_idx: previously registered callback handle
675 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800676 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 * module is unloaded.
678 */
679void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530680mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600682 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 MptCallbacks[cb_idx] = NULL;
684 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
685 MptEvHandlers[cb_idx] = NULL;
686
687 last_drv_idx++;
688 }
689}
690
691/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
692/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800693 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 * @cb_idx: previously registered (via mpt_register) callback handle
695 * @ev_cbfunc: callback function
696 *
697 * This routine can be called by one or more protocol-specific drivers
698 * if/when they choose to be notified of MPT events.
699 *
700 * Returns 0 for success.
701 */
702int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530703mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600705 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 return -1;
707
708 MptEvHandlers[cb_idx] = ev_cbfunc;
709 return 0;
710}
711
712/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
713/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800714 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 * @cb_idx: previously registered callback handle
716 *
717 * Each protocol-specific driver should call this routine
718 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800719 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 */
721void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530722mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600724 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 return;
726
727 MptEvHandlers[cb_idx] = NULL;
728}
729
730/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
731/**
732 * mpt_reset_register - Register protocol-specific IOC reset handler.
733 * @cb_idx: previously registered (via mpt_register) callback handle
734 * @reset_func: reset function
735 *
736 * This routine can be called by one or more protocol-specific drivers
737 * if/when they choose to be notified of IOC resets.
738 *
739 * Returns 0 for success.
740 */
741int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530742mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530744 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 return -1;
746
747 MptResetHandlers[cb_idx] = reset_func;
748 return 0;
749}
750
751/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
752/**
753 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
754 * @cb_idx: previously registered callback handle
755 *
756 * Each protocol-specific driver should call this routine
757 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800758 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 */
760void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530761mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530763 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 return;
765
766 MptResetHandlers[cb_idx] = NULL;
767}
768
769/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
770/**
771 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800772 * @dd_cbfunc: driver callbacks struct
773 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 */
775int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530776mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777{
778 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600779 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
Eric Moore8d6d83e2007-09-14 18:47:40 -0600781 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400782 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
784 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
785
786 /* call per pci device probe entry point */
787 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600788 id = ioc->pcidev->driver ?
789 ioc->pcidev->driver->id_table : NULL;
790 if (dd_cbfunc->probe)
791 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 }
793
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400794 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795}
796
797/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
798/**
799 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800800 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 */
802void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530803mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804{
805 struct mpt_pci_driver *dd_cbfunc;
806 MPT_ADAPTER *ioc;
807
Eric Moore8d6d83e2007-09-14 18:47:40 -0600808 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 return;
810
811 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
812
813 list_for_each_entry(ioc, &ioc_list, list) {
814 if (dd_cbfunc->remove)
815 dd_cbfunc->remove(ioc->pcidev);
816 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200817
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 MptDeviceDriverHandlers[cb_idx] = NULL;
819}
820
821
822/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
823/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800824 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530825 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 * @ioc: Pointer to MPT adapter structure
827 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800828 * Obtain an MPT request frame from the pool (of 1024) that are
829 * allocated per MPT adapter.
830 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 * Returns pointer to a MPT request frame or %NULL if none are available
832 * or IOC is not active.
833 */
834MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530835mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836{
837 MPT_FRAME_HDR *mf;
838 unsigned long flags;
839 u16 req_idx; /* Request index */
840
841 /* validate handle and ioc identifier */
842
843#ifdef MFCNT
844 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600845 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
846 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847#endif
848
849 /* If interrupts are not attached, do not return a request frame */
850 if (!ioc->active)
851 return NULL;
852
853 spin_lock_irqsave(&ioc->FreeQlock, flags);
854 if (!list_empty(&ioc->FreeQ)) {
855 int req_offset;
856
857 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
858 u.frame.linkage.list);
859 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200860 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530861 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
863 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500864 req_idx = req_offset / ioc->req_sz;
865 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600867 /* Default, will be changed if necessary in SG generation */
868 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869#ifdef MFCNT
870 ioc->mfcnt++;
871#endif
872 }
873 else
874 mf = NULL;
875 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
876
877#ifdef MFCNT
878 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600879 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
880 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
881 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 mfcounter++;
883 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600884 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
885 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886#endif
887
Eric Moore29dd3602007-09-14 18:46:51 -0600888 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
889 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 return mf;
891}
892
893/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
894/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800895 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530896 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 * @ioc: Pointer to MPT adapter structure
898 * @mf: Pointer to MPT request frame
899 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800900 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 * specific MPT adapter.
902 */
903void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530904mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905{
906 u32 mf_dma_addr;
907 int req_offset;
908 u16 req_idx; /* Request index */
909
910 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530911 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
913 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500914 req_idx = req_offset / ioc->req_sz;
915 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
917
Prakash, Sathya436ace72007-07-24 15:42:08 +0530918 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200920 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600921 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
922 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
923 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
925}
926
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530927/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800928 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530929 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530930 * @ioc: Pointer to MPT adapter structure
931 * @mf: Pointer to MPT request frame
932 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800933 * Send a protocol-specific MPT request frame to an IOC using
934 * hi-priority request queue.
935 *
936 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530937 * specific MPT adapter.
938 **/
939void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530940mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530941{
942 u32 mf_dma_addr;
943 int req_offset;
944 u16 req_idx; /* Request index */
945
946 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530947 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530948 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
949 req_idx = req_offset / ioc->req_sz;
950 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
951 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
952
953 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
954
955 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
956 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
957 ioc->name, mf_dma_addr, req_idx));
958 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
959}
960
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
962/**
963 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 * @ioc: Pointer to MPT adapter structure
965 * @mf: Pointer to MPT request frame
966 *
967 * This routine places a MPT request frame back on the MPT adapter's
968 * FreeQ.
969 */
970void
971mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
972{
973 unsigned long flags;
974
975 /* Put Request back on FreeQ! */
976 spin_lock_irqsave(&ioc->FreeQlock, flags);
Kashyap, Desai2f187862009-05-29 16:52:37 +0530977 if (cpu_to_le32(mf->u.frame.linkage.arg1) == 0xdeadbeaf)
978 goto out;
979 /* signature to know if this mf is freed */
980 mf->u.frame.linkage.arg1 = cpu_to_le32(0xdeadbeaf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
982#ifdef MFCNT
983 ioc->mfcnt--;
984#endif
Kashyap, Desai2f187862009-05-29 16:52:37 +0530985 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
987}
988
989/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
990/**
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530991 * mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 * @pAddr: virtual address for SGE
993 * @flagslength: SGE flags and data transfer length
994 * @dma_addr: Physical address
995 *
996 * This routine places a MPT request frame back on the MPT adapter's
997 * FreeQ.
998 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530999static void
1000mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001{
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301002 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
1003 pSge->FlagsLength = cpu_to_le32(flagslength);
1004 pSge->Address = cpu_to_le32(dma_addr);
1005}
1006
1007/**
1008 * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
1009 * @pAddr: virtual address for SGE
1010 * @flagslength: SGE flags and data transfer length
1011 * @dma_addr: Physical address
1012 *
1013 * This routine places a MPT request frame back on the MPT adapter's
1014 * FreeQ.
1015 **/
1016static void
1017mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1018{
1019 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1020 pSge->Address.Low = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301021 (lower_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301022 pSge->Address.High = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301023 (upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301024 pSge->FlagsLength = cpu_to_le32
1025 ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1026}
1027
1028/**
Randy Dunlap9cf46a32009-06-13 19:37:18 -07001029 * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr (1078 workaround).
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301030 * @pAddr: virtual address for SGE
1031 * @flagslength: SGE flags and data transfer length
1032 * @dma_addr: Physical address
1033 *
1034 * This routine places a MPT request frame back on the MPT adapter's
1035 * FreeQ.
1036 **/
1037static void
1038mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1039{
1040 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1041 u32 tmp;
1042
1043 pSge->Address.Low = cpu_to_le32
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301044 (lower_32_bits(dma_addr));
1045 tmp = (u32)(upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301046
1047 /*
1048 * 1078 errata workaround for the 36GB limitation
1049 */
1050 if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {
1051 flagslength |=
1052 MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
1053 tmp |= (1<<31);
1054 if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
1055 printk(KERN_DEBUG "1078 P0M2 addressing for "
1056 "addr = 0x%llx len = %d\n",
1057 (unsigned long long)dma_addr,
1058 MPI_SGE_LENGTH(flagslength));
1059 }
1060
1061 pSge->Address.High = cpu_to_le32(tmp);
1062 pSge->FlagsLength = cpu_to_le32(
1063 (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1064}
1065
1066/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1067/**
1068 * mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
1069 * @pAddr: virtual address for SGE
1070 * @next: nextChainOffset value (u32's)
1071 * @length: length of next SGL segment
1072 * @dma_addr: Physical address
1073 *
1074 */
1075static void
1076mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1077{
1078 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
1079 pChain->Length = cpu_to_le16(length);
1080 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
1081 pChain->NextChainOffset = next;
1082 pChain->Address = cpu_to_le32(dma_addr);
1083}
1084
1085/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1086/**
1087 * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
1088 * @pAddr: virtual address for SGE
1089 * @next: nextChainOffset value (u32's)
1090 * @length: length of next SGL segment
1091 * @dma_addr: Physical address
1092 *
1093 */
1094static void
1095mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1096{
1097 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 u32 tmp = dma_addr & 0xFFFFFFFF;
1099
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301100 pChain->Length = cpu_to_le16(length);
1101 pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
1102 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301104 pChain->NextChainOffset = next;
1105
1106 pChain->Address.Low = cpu_to_le32(tmp);
Kashyap, Desaic55b89f2009-09-02 11:44:57 +05301107 tmp = (u32)(upper_32_bits(dma_addr));
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301108 pChain->Address.High = cpu_to_le32(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109}
1110
1111/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1112/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001113 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301114 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 * @ioc: Pointer to MPT adapter structure
1116 * @reqBytes: Size of the request in bytes
1117 * @req: Pointer to MPT request frame
1118 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1119 *
1120 * This routine is used exclusively to send MptScsiTaskMgmt
1121 * requests since they are required to be sent via doorbell handshake.
1122 *
1123 * NOTE: It is the callers responsibility to byte-swap fields in the
1124 * request which are greater than 1 byte in size.
1125 *
1126 * Returns 0 for success, non-zero for failure.
1127 */
1128int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301129mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130{
Eric Moorecd2c6192007-01-29 09:47:47 -07001131 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 u8 *req_as_bytes;
1133 int ii;
1134
1135 /* State is known to be good upon entering
1136 * this function so issue the bus reset
1137 * request.
1138 */
1139
1140 /*
1141 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1142 * setting cb_idx/req_idx. But ONLY if this request
1143 * is in proper (pre-alloc'd) request buffer range...
1144 */
1145 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1146 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1147 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1148 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301149 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 }
1151
1152 /* Make sure there are no doorbells */
1153 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001154
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1156 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1157 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1158
1159 /* Wait for IOC doorbell int */
1160 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1161 return ii;
1162 }
1163
1164 /* Read doorbell and check for active bit */
1165 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1166 return -5;
1167
Eric Moore29dd3602007-09-14 18:46:51 -06001168 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001169 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170
1171 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1172
1173 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1174 return -2;
1175 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001176
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 /* Send request via doorbell handshake */
1178 req_as_bytes = (u8 *) req;
1179 for (ii = 0; ii < reqBytes/4; ii++) {
1180 u32 word;
1181
1182 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1183 (req_as_bytes[(ii*4) + 1] << 8) |
1184 (req_as_bytes[(ii*4) + 2] << 16) |
1185 (req_as_bytes[(ii*4) + 3] << 24));
1186 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1187 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1188 r = -3;
1189 break;
1190 }
1191 }
1192
1193 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1194 r = 0;
1195 else
1196 r = -4;
1197
1198 /* Make sure there are no doorbells */
1199 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001200
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 return r;
1202}
1203
1204/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1205/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001206 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001207 * @ioc: Pointer to MPT adapter structure
1208 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001209 * @sleepFlag: Specifies whether the process can sleep
1210 *
1211 * Provides mechanism for the host driver to control the IOC's
1212 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001213 *
1214 * Access Control Value - bits[15:12]
1215 * 0h Reserved
1216 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1217 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1218 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1219 *
1220 * Returns 0 for success, non-zero for failure.
1221 */
1222
1223static int
1224mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1225{
1226 int r = 0;
1227
1228 /* return if in use */
1229 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1230 & MPI_DOORBELL_ACTIVE)
1231 return -1;
1232
1233 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1234
1235 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1236 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1237 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1238 (access_control_value<<12)));
1239
1240 /* Wait for IOC to clear Doorbell Status bit */
1241 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1242 return -2;
1243 }else
1244 return 0;
1245}
1246
1247/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1248/**
1249 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001250 * @ioc: Pointer to pointer to IOC adapter
1251 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001252 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001253 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001254 * Returns 0 for success, non-zero for failure.
1255 */
1256static int
1257mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1258{
1259 char *psge;
1260 int flags_length;
1261 u32 host_page_buffer_sz=0;
1262
1263 if(!ioc->HostPageBuffer) {
1264
1265 host_page_buffer_sz =
1266 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1267
1268 if(!host_page_buffer_sz)
1269 return 0; /* fw doesn't need any host buffers */
1270
1271 /* spin till we get enough memory */
1272 while(host_page_buffer_sz > 0) {
1273
1274 if((ioc->HostPageBuffer = pci_alloc_consistent(
1275 ioc->pcidev,
1276 host_page_buffer_sz,
1277 &ioc->HostPageBuffer_dma)) != NULL) {
1278
Prakash, Sathya436ace72007-07-24 15:42:08 +05301279 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001280 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001281 ioc->name, ioc->HostPageBuffer,
1282 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001283 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001284 ioc->alloc_total += host_page_buffer_sz;
1285 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1286 break;
1287 }
1288
1289 host_page_buffer_sz -= (4*1024);
1290 }
1291 }
1292
1293 if(!ioc->HostPageBuffer) {
1294 printk(MYIOC_s_ERR_FMT
1295 "Failed to alloc memory for host_page_buffer!\n",
1296 ioc->name);
1297 return -999;
1298 }
1299
1300 psge = (char *)&ioc_init->HostPageBufferSGE;
1301 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1302 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001303 MPI_SGE_FLAGS_HOST_TO_IOC |
1304 MPI_SGE_FLAGS_END_OF_BUFFER;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001305 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1306 flags_length |= ioc->HostPageBuffer_sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301307 ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001308 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1309
1310return 0;
1311}
1312
1313/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1314/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001315 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 * @iocid: IOC unique identifier (integer)
1317 * @iocpp: Pointer to pointer to IOC adapter
1318 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001319 * Given a unique IOC identifier, set pointer to the associated MPT
1320 * adapter structure.
1321 *
1322 * Returns iocid and sets iocpp if iocid is found.
1323 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 */
1325int
1326mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1327{
1328 MPT_ADAPTER *ioc;
1329
1330 list_for_each_entry(ioc,&ioc_list,list) {
1331 if (ioc->id == iocid) {
1332 *iocpp =ioc;
1333 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001334 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001336
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 *iocpp = NULL;
1338 return -1;
1339}
1340
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301341/**
1342 * mpt_get_product_name - returns product string
1343 * @vendor: pci vendor id
1344 * @device: pci device id
1345 * @revision: pci revision id
1346 * @prod_name: string returned
1347 *
1348 * Returns product string displayed when driver loads,
1349 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1350 *
1351 **/
1352static void
1353mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1354{
1355 char *product_str = NULL;
1356
1357 if (vendor == PCI_VENDOR_ID_BROCADE) {
1358 switch (device)
1359 {
1360 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1361 switch (revision)
1362 {
1363 case 0x00:
1364 product_str = "BRE040 A0";
1365 break;
1366 case 0x01:
1367 product_str = "BRE040 A1";
1368 break;
1369 default:
1370 product_str = "BRE040";
1371 break;
1372 }
1373 break;
1374 }
1375 goto out;
1376 }
1377
1378 switch (device)
1379 {
1380 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1381 product_str = "LSIFC909 B1";
1382 break;
1383 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1384 product_str = "LSIFC919 B0";
1385 break;
1386 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1387 product_str = "LSIFC929 B0";
1388 break;
1389 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1390 if (revision < 0x80)
1391 product_str = "LSIFC919X A0";
1392 else
1393 product_str = "LSIFC919XL A1";
1394 break;
1395 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1396 if (revision < 0x80)
1397 product_str = "LSIFC929X A0";
1398 else
1399 product_str = "LSIFC929XL A1";
1400 break;
1401 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1402 product_str = "LSIFC939X A1";
1403 break;
1404 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1405 product_str = "LSIFC949X A1";
1406 break;
1407 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1408 switch (revision)
1409 {
1410 case 0x00:
1411 product_str = "LSIFC949E A0";
1412 break;
1413 case 0x01:
1414 product_str = "LSIFC949E A1";
1415 break;
1416 default:
1417 product_str = "LSIFC949E";
1418 break;
1419 }
1420 break;
1421 case MPI_MANUFACTPAGE_DEVID_53C1030:
1422 switch (revision)
1423 {
1424 case 0x00:
1425 product_str = "LSI53C1030 A0";
1426 break;
1427 case 0x01:
1428 product_str = "LSI53C1030 B0";
1429 break;
1430 case 0x03:
1431 product_str = "LSI53C1030 B1";
1432 break;
1433 case 0x07:
1434 product_str = "LSI53C1030 B2";
1435 break;
1436 case 0x08:
1437 product_str = "LSI53C1030 C0";
1438 break;
1439 case 0x80:
1440 product_str = "LSI53C1030T A0";
1441 break;
1442 case 0x83:
1443 product_str = "LSI53C1030T A2";
1444 break;
1445 case 0x87:
1446 product_str = "LSI53C1030T A3";
1447 break;
1448 case 0xc1:
1449 product_str = "LSI53C1020A A1";
1450 break;
1451 default:
1452 product_str = "LSI53C1030";
1453 break;
1454 }
1455 break;
1456 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1457 switch (revision)
1458 {
1459 case 0x03:
1460 product_str = "LSI53C1035 A2";
1461 break;
1462 case 0x04:
1463 product_str = "LSI53C1035 B0";
1464 break;
1465 default:
1466 product_str = "LSI53C1035";
1467 break;
1468 }
1469 break;
1470 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1471 switch (revision)
1472 {
1473 case 0x00:
1474 product_str = "LSISAS1064 A1";
1475 break;
1476 case 0x01:
1477 product_str = "LSISAS1064 A2";
1478 break;
1479 case 0x02:
1480 product_str = "LSISAS1064 A3";
1481 break;
1482 case 0x03:
1483 product_str = "LSISAS1064 A4";
1484 break;
1485 default:
1486 product_str = "LSISAS1064";
1487 break;
1488 }
1489 break;
1490 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1491 switch (revision)
1492 {
1493 case 0x00:
1494 product_str = "LSISAS1064E A0";
1495 break;
1496 case 0x01:
1497 product_str = "LSISAS1064E B0";
1498 break;
1499 case 0x02:
1500 product_str = "LSISAS1064E B1";
1501 break;
1502 case 0x04:
1503 product_str = "LSISAS1064E B2";
1504 break;
1505 case 0x08:
1506 product_str = "LSISAS1064E B3";
1507 break;
1508 default:
1509 product_str = "LSISAS1064E";
1510 break;
1511 }
1512 break;
1513 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1514 switch (revision)
1515 {
1516 case 0x00:
1517 product_str = "LSISAS1068 A0";
1518 break;
1519 case 0x01:
1520 product_str = "LSISAS1068 B0";
1521 break;
1522 case 0x02:
1523 product_str = "LSISAS1068 B1";
1524 break;
1525 default:
1526 product_str = "LSISAS1068";
1527 break;
1528 }
1529 break;
1530 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1531 switch (revision)
1532 {
1533 case 0x00:
1534 product_str = "LSISAS1068E A0";
1535 break;
1536 case 0x01:
1537 product_str = "LSISAS1068E B0";
1538 break;
1539 case 0x02:
1540 product_str = "LSISAS1068E B1";
1541 break;
1542 case 0x04:
1543 product_str = "LSISAS1068E B2";
1544 break;
1545 case 0x08:
1546 product_str = "LSISAS1068E B3";
1547 break;
1548 default:
1549 product_str = "LSISAS1068E";
1550 break;
1551 }
1552 break;
1553 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1554 switch (revision)
1555 {
1556 case 0x00:
1557 product_str = "LSISAS1078 A0";
1558 break;
1559 case 0x01:
1560 product_str = "LSISAS1078 B0";
1561 break;
1562 case 0x02:
1563 product_str = "LSISAS1078 C0";
1564 break;
1565 case 0x03:
1566 product_str = "LSISAS1078 C1";
1567 break;
1568 case 0x04:
1569 product_str = "LSISAS1078 C2";
1570 break;
1571 default:
1572 product_str = "LSISAS1078";
1573 break;
1574 }
1575 break;
1576 }
1577
1578 out:
1579 if (product_str)
1580 sprintf(prod_name, "%s", product_str);
1581}
1582
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301583/**
1584 * mpt_mapresources - map in memory mapped io
1585 * @ioc: Pointer to pointer to IOC adapter
1586 *
1587 **/
1588static int
1589mpt_mapresources(MPT_ADAPTER *ioc)
1590{
1591 u8 __iomem *mem;
1592 int ii;
Pravin Bathijae46b63b2009-12-02 17:51:46 -08001593 resource_size_t mem_phys;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301594 unsigned long port;
1595 u32 msize;
1596 u32 psize;
1597 u8 revision;
1598 int r = -ENODEV;
1599 struct pci_dev *pdev;
1600
1601 pdev = ioc->pcidev;
1602 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1603 if (pci_enable_device_mem(pdev)) {
1604 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1605 "failed\n", ioc->name);
1606 return r;
1607 }
1608 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1609 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1610 "MEM failed\n", ioc->name);
1611 return r;
1612 }
1613
1614 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1615
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301616 if (sizeof(dma_addr_t) > 4) {
1617 const uint64_t required_mask = dma_get_required_mask
1618 (&pdev->dev);
1619 if (required_mask > DMA_BIT_MASK(32)
1620 && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
1621 && !pci_set_consistent_dma_mask(pdev,
1622 DMA_BIT_MASK(64))) {
1623 ioc->dma_mask = DMA_BIT_MASK(64);
1624 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1625 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1626 ioc->name));
1627 } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1628 && !pci_set_consistent_dma_mask(pdev,
1629 DMA_BIT_MASK(32))) {
1630 ioc->dma_mask = DMA_BIT_MASK(32);
1631 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1632 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1633 ioc->name));
1634 } else {
1635 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1636 ioc->name, pci_name(pdev));
Tomas Henzl653c42d2010-07-26 16:41:13 +02001637 pci_release_selected_regions(pdev, ioc->bars);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301638 return r;
1639 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301640 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301641 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1642 && !pci_set_consistent_dma_mask(pdev,
1643 DMA_BIT_MASK(32))) {
1644 ioc->dma_mask = DMA_BIT_MASK(32);
1645 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1646 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1647 ioc->name));
1648 } else {
1649 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1650 ioc->name, pci_name(pdev));
Tomas Henzl653c42d2010-07-26 16:41:13 +02001651 pci_release_selected_regions(pdev, ioc->bars);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301652 return r;
1653 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301654 }
1655
1656 mem_phys = msize = 0;
1657 port = psize = 0;
1658 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1659 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1660 if (psize)
1661 continue;
1662 /* Get I/O space! */
1663 port = pci_resource_start(pdev, ii);
1664 psize = pci_resource_len(pdev, ii);
1665 } else {
1666 if (msize)
1667 continue;
1668 /* Get memmap */
1669 mem_phys = pci_resource_start(pdev, ii);
1670 msize = pci_resource_len(pdev, ii);
1671 }
1672 }
1673 ioc->mem_size = msize;
1674
1675 mem = NULL;
1676 /* Get logical ptr for PciMem0 space */
1677 /*mem = ioremap(mem_phys, msize);*/
1678 mem = ioremap(mem_phys, msize);
1679 if (mem == NULL) {
1680 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1681 " memory!\n", ioc->name);
Tomas Henzl653c42d2010-07-26 16:41:13 +02001682 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301683 return -EINVAL;
1684 }
1685 ioc->memmap = mem;
Pravin Bathijae46b63b2009-12-02 17:51:46 -08001686 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %llx\n",
1687 ioc->name, mem, (unsigned long long)mem_phys));
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301688
1689 ioc->mem_phys = mem_phys;
1690 ioc->chip = (SYSIF_REGS __iomem *)mem;
1691
1692 /* Save Port IO values in case we need to do downloadboot */
1693 ioc->pio_mem_phys = port;
1694 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1695
1696 return 0;
1697}
1698
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001700/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001701 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001703 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 *
1705 * This routine performs all the steps necessary to bring the IOC of
1706 * a MPT adapter to a OPERATIONAL state. This includes registering
1707 * memory regions, registering the interrupt, and allocating request
1708 * and reply memory pools.
1709 *
1710 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1711 * MPT adapter.
1712 *
1713 * Returns 0 for success, non-zero for failure.
1714 *
1715 * TODO: Add support for polled controllers
1716 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001717int
1718mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719{
1720 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301721 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 u8 revision;
1724 u8 pcixcmd;
1725 static int mpt_ids = 0;
1726#ifdef CONFIG_PROC_FS
1727 struct proc_dir_entry *dent, *ent;
1728#endif
1729
Jesper Juhl56876192007-08-10 14:50:51 -07001730 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1731 if (ioc == NULL) {
1732 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1733 return -ENOMEM;
1734 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301735
Eric Moore29dd3602007-09-14 18:46:51 -06001736 ioc->id = mpt_ids++;
1737 sprintf(ioc->name, "ioc%d", ioc->id);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301738 dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
Jesper Juhl56876192007-08-10 14:50:51 -07001739
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301740 /*
1741 * set initial debug level
1742 * (refer to mptdebug.h)
1743 *
1744 */
1745 ioc->debug_level = mpt_debug_level;
1746 if (mpt_debug_level)
1747 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301748
Eric Moore29dd3602007-09-14 18:46:51 -06001749 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001750
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301751 ioc->pcidev = pdev;
1752 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001753 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 return r;
1755 }
1756
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301757 /*
1758 * Setting up proper handlers for scatter gather handling
1759 */
1760 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
1761 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
1762 ioc->add_sge = &mpt_add_sge_64bit_1078;
1763 else
1764 ioc->add_sge = &mpt_add_sge_64bit;
1765 ioc->add_chain = &mpt_add_chain_64bit;
1766 ioc->sg_addr_size = 8;
1767 } else {
1768 ioc->add_sge = &mpt_add_sge;
1769 ioc->add_chain = &mpt_add_chain;
1770 ioc->sg_addr_size = 4;
1771 }
1772 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
1773
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 ioc->alloc_total = sizeof(MPT_ADAPTER);
1775 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1776 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001777
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301779 spin_lock_init(&ioc->taskmgmt_lock);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05301780 mutex_init(&ioc->internal_cmds.mutex);
1781 init_completion(&ioc->internal_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301782 mutex_init(&ioc->mptbase_cmds.mutex);
1783 init_completion(&ioc->mptbase_cmds.done);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301784 mutex_init(&ioc->taskmgmt_cmds.mutex);
1785 init_completion(&ioc->taskmgmt_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301786
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 /* Initialize the event logging.
1788 */
1789 ioc->eventTypes = 0; /* None */
1790 ioc->eventContext = 0;
1791 ioc->eventLogSize = 0;
1792 ioc->events = NULL;
1793
1794#ifdef MFCNT
1795 ioc->mfcnt = 0;
1796#endif
1797
Kashyap, Desai2f187862009-05-29 16:52:37 +05301798 ioc->sh = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 ioc->cached_fw = NULL;
1800
Uwe Kleine-König421f91d2010-06-11 12:17:00 +02001801 /* Initialize SCSI Config Data structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001803 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804
Michael Reed05e8ec12006-01-13 14:31:54 -06001805 /* Initialize the fc rport list head.
1806 */
1807 INIT_LIST_HEAD(&ioc->fc_rports);
1808
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 /* Find lookup slot. */
1810 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001811
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301812
1813 /* Initialize workqueue */
1814 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301815
Kashyap, Desai2f187862009-05-29 16:52:37 +05301816 snprintf(ioc->reset_work_q_name, MPT_KOBJ_NAME_LEN,
Kay Sieversaab0de22008-05-02 06:02:41 +02001817 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301818 ioc->reset_work_q =
1819 create_singlethread_workqueue(ioc->reset_work_q_name);
1820 if (!ioc->reset_work_q) {
1821 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1822 ioc->name);
1823 pci_release_selected_regions(pdev, ioc->bars);
1824 kfree(ioc);
1825 return -ENOMEM;
1826 }
1827
Eric Moore29dd3602007-09-14 18:46:51 -06001828 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1829 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301831 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1832 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1833
1834 switch (pdev->device)
1835 {
1836 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1837 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1838 ioc->errata_flag_1064 = 1;
1839 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1840 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1841 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1842 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301844 break;
1845
1846 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 /* 929X Chip Fix. Set Split transactions level
1849 * for PCIX. Set MOST bits to zero.
1850 */
1851 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1852 pcixcmd &= 0x8F;
1853 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1854 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 /* 929XL Chip Fix. Set MMRBC to 0x08.
1856 */
1857 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1858 pcixcmd |= 0x08;
1859 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1860 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301862 break;
1863
1864 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 /* 919X Chip Fix. Set Split transactions level
1866 * for PCIX. Set MOST bits to zero.
1867 */
1868 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1869 pcixcmd &= 0x8F;
1870 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001871 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301872 break;
1873
1874 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 /* 1030 Chip Fix. Disable Split transactions
1876 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1877 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 if (revision < C0_1030) {
1879 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1880 pcixcmd &= 0x8F;
1881 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1882 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301883
1884 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001885 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301886 break;
1887
1888 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1889 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001890 ioc->errata_flag_1064 = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301891 ioc->bus_type = SAS;
1892 break;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301893
1894 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1895 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1896 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001897 ioc->bus_type = SAS;
Kashyap, Desai2f187862009-05-29 16:52:37 +05301898 break;
Eric Moore87cf8982006-06-27 16:09:26 -06001899 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301901
Kashyap, Desaie3829682009-01-08 14:27:16 +05301902 switch (ioc->bus_type) {
1903
1904 case SAS:
1905 ioc->msi_enable = mpt_msi_enable_sas;
1906 break;
1907
1908 case SPI:
1909 ioc->msi_enable = mpt_msi_enable_spi;
1910 break;
1911
1912 case FC:
1913 ioc->msi_enable = mpt_msi_enable_fc;
1914 break;
1915
1916 default:
1917 ioc->msi_enable = 0;
1918 break;
1919 }
Kashyap, Desai8ce13de2010-06-17 14:35:46 +05301920
1921 ioc->fw_events_off = 1;
1922
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001923 if (ioc->errata_flag_1064)
1924 pci_disable_io_access(pdev);
1925
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 spin_lock_init(&ioc->FreeQlock);
1927
1928 /* Disable all! */
1929 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1930 ioc->active = 0;
1931 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1932
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301933 /* Set IOC ptr in the pcidev's driver data. */
1934 pci_set_drvdata(ioc->pcidev, ioc);
1935
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 /* Set lookup ptr. */
1937 list_add_tail(&ioc->list, &ioc_list);
1938
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001939 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 */
1941 mpt_detect_bound_ports(ioc, pdev);
1942
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301943 INIT_LIST_HEAD(&ioc->fw_event_list);
1944 spin_lock_init(&ioc->fw_event_lock);
Kashyap, Desai2f187862009-05-29 16:52:37 +05301945 snprintf(ioc->fw_event_q_name, MPT_KOBJ_NAME_LEN, "mpt/%d", ioc->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301946 ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
1947
James Bottomleyc92f2222006-03-01 09:02:49 -06001948 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1949 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001950 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1951 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001952
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001954 if (ioc->alt_ioc)
1955 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301956 iounmap(ioc->memmap);
1957 if (r != -5)
1958 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301959
1960 destroy_workqueue(ioc->reset_work_q);
1961 ioc->reset_work_q = NULL;
1962
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 kfree(ioc);
1964 pci_set_drvdata(pdev, NULL);
1965 return r;
1966 }
1967
1968 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001969 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301970 if(MptDeviceDriverHandlers[cb_idx] &&
1971 MptDeviceDriverHandlers[cb_idx]->probe) {
1972 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 }
1974 }
1975
1976#ifdef CONFIG_PROC_FS
1977 /*
1978 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1979 */
1980 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1981 if (dent) {
1982 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1983 if (ent) {
1984 ent->read_proc = procmpt_iocinfo_read;
1985 ent->data = ioc;
1986 }
1987 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1988 if (ent) {
1989 ent->read_proc = procmpt_summary_read;
1990 ent->data = ioc;
1991 }
1992 }
1993#endif
1994
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301995 if (!ioc->alt_ioc)
1996 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1997 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1998
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 return 0;
2000}
2001
2002/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002003/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002004 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 */
2007
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002008void
2009mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010{
2011 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2012 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302013 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302014 unsigned long flags;
2015 struct workqueue_struct *wq;
2016
2017 /*
2018 * Stop polling ioc for fault condition
2019 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302020 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302021 wq = ioc->reset_work_q;
2022 ioc->reset_work_q = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302023 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302024 cancel_delayed_work(&ioc->fault_reset_work);
2025 destroy_workqueue(wq);
2026
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05302027 spin_lock_irqsave(&ioc->fw_event_lock, flags);
2028 wq = ioc->fw_event_q;
2029 ioc->fw_event_q = NULL;
2030 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2031 destroy_workqueue(wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032
2033 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2034 remove_proc_entry(pname, NULL);
2035 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2036 remove_proc_entry(pname, NULL);
2037 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2038 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002039
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002041 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302042 if(MptDeviceDriverHandlers[cb_idx] &&
2043 MptDeviceDriverHandlers[cb_idx]->remove) {
2044 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 }
2046 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002047
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 /* Disable interrupts! */
2049 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2050
2051 ioc->active = 0;
2052 synchronize_irq(pdev->irq);
2053
2054 /* Clear any lingering interrupt */
2055 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2056
2057 CHIPREG_READ32(&ioc->chip->IntStatus);
2058
2059 mpt_adapter_dispose(ioc);
2060
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061}
2062
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063/**************************************************************************
2064 * Power Management
2065 */
2066#ifdef CONFIG_PM
2067/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002068/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002069 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002070 * @pdev: Pointer to pci_dev structure
2071 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002073int
2074mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075{
2076 u32 device_state;
2077 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302079 device_state = pci_choose_state(pdev, state);
2080 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2081 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2082 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083
2084 /* put ioc into READY_STATE */
2085 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2086 printk(MYIOC_s_ERR_FMT
2087 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2088 }
2089
2090 /* disable interrupts */
2091 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2092 ioc->active = 0;
2093
2094 /* Clear any lingering interrupt */
2095 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2096
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302097 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002098 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302099 pci_disable_msi(ioc->pcidev);
2100 ioc->pci_irq = -1;
2101 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302103 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 return 0;
2106}
2107
2108/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002109/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002110 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002111 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002113int
2114mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115{
2116 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2117 u32 device_state = pdev->current_state;
2118 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302119 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002120
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302121 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2122 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2123 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302125 pci_set_power_state(pdev, PCI_D0);
2126 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302128 ioc->pcidev = pdev;
2129 err = mpt_mapresources(ioc);
2130 if (err)
2131 return err;
2132
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302133 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2134 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2135 ioc->add_sge = &mpt_add_sge_64bit_1078;
2136 else
2137 ioc->add_sge = &mpt_add_sge_64bit;
2138 ioc->add_chain = &mpt_add_chain_64bit;
2139 ioc->sg_addr_size = 8;
2140 } else {
2141
2142 ioc->add_sge = &mpt_add_sge;
2143 ioc->add_chain = &mpt_add_chain;
2144 ioc->sg_addr_size = 4;
2145 }
2146 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2147
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302148 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2149 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2150 CHIPREG_READ32(&ioc->chip->Doorbell));
2151
2152 /*
2153 * Errata workaround for SAS pci express:
2154 * Upon returning to the D0 state, the contents of the doorbell will be
2155 * stale data, and this will incorrectly signal to the host driver that
2156 * the firmware is ready to process mpt commands. The workaround is
2157 * to issue a diagnostic reset.
2158 */
2159 if (ioc->bus_type == SAS && (pdev->device ==
2160 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2161 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2162 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2163 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2164 ioc->name);
2165 goto out;
2166 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302167 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168
2169 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302170 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2171 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2172 CAN_SLEEP);
2173 if (recovery_state != 0)
2174 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2175 "error:[%x]\n", ioc->name, recovery_state);
2176 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302178 "pci-resume: success\n", ioc->name);
2179 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302181
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182}
2183#endif
2184
James Bottomley4ff42a62006-05-17 18:06:52 -05002185static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302186mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002187{
2188 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2189 ioc->bus_type != SPI) ||
2190 (MptDriverClass[index] == MPTFC_DRIVER &&
2191 ioc->bus_type != FC) ||
2192 (MptDriverClass[index] == MPTSAS_DRIVER &&
2193 ioc->bus_type != SAS))
2194 /* make sure we only call the relevant reset handler
2195 * for the bus */
2196 return 0;
2197 return (MptResetHandlers[index])(ioc, reset_phase);
2198}
2199
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002201/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2203 * @ioc: Pointer to MPT adapter structure
2204 * @reason: Event word / reason
2205 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2206 *
2207 * This routine performs all the steps necessary to bring the IOC
2208 * to a OPERATIONAL state.
2209 *
2210 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2211 * MPT adapter.
2212 *
2213 * Returns:
2214 * 0 for success
2215 * -1 if failed to get board READY
2216 * -2 if READY but IOCFacts Failed
2217 * -3 if READY but PrimeIOCFifos Failed
2218 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302219 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302220 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 */
2222static int
2223mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2224{
2225 int hard_reset_done = 0;
2226 int alt_ioc_ready = 0;
2227 int hard;
2228 int rc=0;
2229 int ii;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 int ret = 0;
2231 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002232 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302233 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
Eric Moore29dd3602007-09-14 18:46:51 -06002235 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2236 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237
2238 /* Disable reply interrupts (also blocks FreeQ) */
2239 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2240 ioc->active = 0;
2241
2242 if (ioc->alt_ioc) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302243 if (ioc->alt_ioc->active ||
2244 reason == MPT_HOSTEVENT_IOC_RECOVER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 reset_alt_ioc_active = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302246 /* Disable alt-IOC's reply interrupts
2247 * (and FreeQ) for a bit
2248 **/
2249 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2250 0xFFFFFFFF);
2251 ioc->alt_ioc->active = 0;
2252 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 }
2254
2255 hard = 1;
2256 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2257 hard = 0;
2258
2259 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2260 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002261 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2262 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263
2264 if (reset_alt_ioc_active && ioc->alt_ioc) {
2265 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002266 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2267 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002268 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 ioc->alt_ioc->active = 1;
2270 }
2271
2272 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302273 printk(MYIOC_s_WARN_FMT
2274 "NOT READY WARNING!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302276 ret = -1;
2277 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 }
2279
2280 /* hard_reset_done = 0 if a soft reset was performed
2281 * and 1 if a hard reset was performed.
2282 */
2283 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2284 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2285 alt_ioc_ready = 1;
2286 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05302287 printk(MYIOC_s_WARN_FMT
2288 ": alt-ioc Not ready WARNING!\n",
2289 ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 }
2291
2292 for (ii=0; ii<5; ii++) {
2293 /* Get IOC facts! Allow 5 retries */
2294 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2295 break;
2296 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002297
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298
2299 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002300 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2301 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 ret = -2;
2303 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2304 MptDisplayIocCapabilities(ioc);
2305 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002306
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 if (alt_ioc_ready) {
2308 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302309 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302310 "Initial Alt IocFacts failed rc=%x\n",
2311 ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 /* Retry - alt IOC was initialized once
2313 */
2314 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2315 }
2316 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302317 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002318 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 alt_ioc_ready = 0;
2320 reset_alt_ioc_active = 0;
2321 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2322 MptDisplayIocCapabilities(ioc->alt_ioc);
2323 }
2324 }
2325
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302326 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2327 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2328 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2329 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2330 IORESOURCE_IO);
2331 if (pci_enable_device(ioc->pcidev))
2332 return -5;
2333 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2334 "mpt"))
2335 return -5;
2336 }
2337
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002338 /*
2339 * Device is reset now. It must have de-asserted the interrupt line
2340 * (if it was asserted) and it should be safe to register for the
2341 * interrupt now.
2342 */
2343 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2344 ioc->pci_irq = -1;
2345 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302346 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002347 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002348 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302349 else
2350 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002351 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002352 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002353 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002354 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Kashyap, Desai2f187862009-05-29 16:52:37 +05302355 "interrupt %d!\n",
2356 ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302357 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002358 pci_disable_msi(ioc->pcidev);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302359 ret = -EBUSY;
2360 goto out;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002361 }
2362 irq_allocated = 1;
2363 ioc->pci_irq = ioc->pcidev->irq;
2364 pci_set_master(ioc->pcidev); /* ?? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302365 pci_set_drvdata(ioc->pcidev, ioc);
2366 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2367 "installed at interrupt %d\n", ioc->name,
2368 ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002369 }
2370 }
2371
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 /* Prime reply & request queues!
2373 * (mucho alloc's) Must be done prior to
2374 * init as upper addresses are needed for init.
2375 * If fails, continue with alt-ioc processing
2376 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302377 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "PrimeIocFifos\n",
2378 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2380 ret = -3;
2381
2382 /* May need to check/upload firmware & data here!
2383 * If fails, continue with alt-ioc processing
2384 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302385 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "SendIocInit\n",
2386 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2388 ret = -4;
2389// NEW!
2390 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302391 printk(MYIOC_s_WARN_FMT
2392 ": alt-ioc (%d) FIFO mgmt alloc WARNING!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002393 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 alt_ioc_ready = 0;
2395 reset_alt_ioc_active = 0;
2396 }
2397
2398 if (alt_ioc_ready) {
2399 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2400 alt_ioc_ready = 0;
2401 reset_alt_ioc_active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302402 printk(MYIOC_s_WARN_FMT
2403 ": alt-ioc: (%d) init failure WARNING!\n",
2404 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 }
2406 }
2407
2408 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2409 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302410 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002411 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412
2413 /* Controller is not operational, cannot do upload
2414 */
2415 if (ret == 0) {
2416 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002417 if (rc == 0) {
2418 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2419 /*
2420 * Maintain only one pointer to FW memory
2421 * so there will not be two attempt to
2422 * downloadboot onboard dual function
2423 * chips (mpt_adapter_disable,
2424 * mpt_diag_reset)
2425 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302426 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002427 "mpt_upload: alt_%s has cached_fw=%p \n",
2428 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302429 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002430 }
2431 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002432 printk(MYIOC_s_WARN_FMT
2433 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302434 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 }
2437 }
2438 }
2439
Kashyap, Desaifd761752009-05-29 16:39:06 +05302440 /* Enable MPT base driver management of EventNotification
2441 * and EventAck handling.
2442 */
2443 if ((ret == 0) && (!ioc->facts.EventState)) {
2444 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2445 "SendEventNotification\n",
2446 ioc->name));
2447 ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
2448 }
2449
2450 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2451 rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
2452
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 if (ret == 0) {
2454 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002455 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 ioc->active = 1;
2457 }
Kashyap, Desaifd761752009-05-29 16:39:06 +05302458 if (rc == 0) { /* alt ioc */
2459 if (reset_alt_ioc_active && ioc->alt_ioc) {
2460 /* (re)Enable alt-IOC! (reply interrupt) */
2461 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
2462 "reply irq re-enabled\n",
2463 ioc->alt_ioc->name));
2464 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2465 MPI_HIM_DIM);
2466 ioc->alt_ioc->active = 1;
2467 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 }
2469
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002471 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2473 * recursive scenario; GetLanConfigPages times out, timer expired
2474 * routine calls HardResetHandler, which calls into here again,
2475 * and we try GetLanConfigPages again...
2476 */
2477 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002478
2479 /*
Uwe Kleine-König421f91d2010-06-11 12:17:00 +02002480 * Initialize link list for inactive raid volumes.
Eric Mooreb506ade2007-01-29 09:45:37 -07002481 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002482 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002483 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2484
Kashyap, Desai2f187862009-05-29 16:52:37 +05302485 switch (ioc->bus_type) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002486
Kashyap, Desai2f187862009-05-29 16:52:37 +05302487 case SAS:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002488 /* clear persistency table */
2489 if(ioc->facts.IOCExceptions &
2490 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2491 ret = mptbase_sas_persist_operation(ioc,
2492 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2493 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002494 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002495 }
2496
2497 /* Find IM volumes
2498 */
2499 mpt_findImVolumes(ioc);
2500
Kashyap, Desai2f187862009-05-29 16:52:37 +05302501 /* Check, and possibly reset, the coalescing value
2502 */
2503 mpt_read_ioc_pg_1(ioc);
2504
2505 break;
2506
2507 case FC:
2508 if ((ioc->pfacts[0].ProtocolFlags &
2509 MPI_PORTFACTS_PROTOCOL_LAN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2511 /*
2512 * Pre-fetch the ports LAN MAC address!
2513 * (LANPage1_t stuff)
2514 */
2515 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302516 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2517 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302518 "LanAddr = %02X:%02X:%02X"
2519 ":%02X:%02X:%02X\n",
2520 ioc->name, a[5], a[4],
2521 a[3], a[2], a[1], a[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302523 break;
2524
2525 case SPI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 /* Get NVRAM and adapter maximums from SPP 0 and 2
2527 */
2528 mpt_GetScsiPortSettings(ioc, 0);
2529
2530 /* Get version and length of SDP 1
2531 */
2532 mpt_readScsiDevicePageHeaders(ioc, 0);
2533
2534 /* Find IM volumes
2535 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002536 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 mpt_findImVolumes(ioc);
2538
2539 /* Check, and possibly reset, the coalescing value
2540 */
2541 mpt_read_ioc_pg_1(ioc);
2542
2543 mpt_read_ioc_pg_4(ioc);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302544
2545 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 }
2547
2548 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302549 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 }
2551
Eric Moore0ccdb002006-07-11 17:33:13 -06002552 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002553 if ((ret != 0) && irq_allocated) {
2554 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302555 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002556 pci_disable_msi(ioc->pcidev);
2557 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 return ret;
2559}
2560
2561/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002562/**
2563 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 * @ioc: Pointer to MPT adapter structure
2565 * @pdev: Pointer to (struct pci_dev) structure
2566 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002567 * Search for PCI bus/dev_function which matches
2568 * PCI bus/dev_function (+/-1) for newly discovered 929,
2569 * 929X, 1030 or 1035.
2570 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2572 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2573 */
2574static void
2575mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2576{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002577 struct pci_dev *peer=NULL;
2578 unsigned int slot = PCI_SLOT(pdev->devfn);
2579 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 MPT_ADAPTER *ioc_srch;
2581
Prakash, Sathya436ace72007-07-24 15:42:08 +05302582 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002583 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002584 ioc->name, pci_name(pdev), pdev->bus->number,
2585 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002586
2587 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2588 if (!peer) {
2589 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2590 if (!peer)
2591 return;
2592 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593
2594 list_for_each_entry(ioc_srch, &ioc_list, list) {
2595 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002596 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 /* Paranoia checks */
2598 if (ioc->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302599 printk(MYIOC_s_WARN_FMT
2600 "Oops, already bound (%s <==> %s)!\n",
2601 ioc->name, ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 break;
2603 } else if (ioc_srch->alt_ioc != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302604 printk(MYIOC_s_WARN_FMT
2605 "Oops, already bound (%s <==> %s)!\n",
2606 ioc_srch->name, ioc_srch->name,
2607 ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 break;
2609 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302610 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2611 "FOUND! binding %s <==> %s\n",
2612 ioc->name, ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 ioc_srch->alt_ioc = ioc;
2614 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 }
2616 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002617 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618}
2619
2620/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002621/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002623 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 */
2625static void
2626mpt_adapter_disable(MPT_ADAPTER *ioc)
2627{
2628 int sz;
2629 int ret;
2630
2631 if (ioc->cached_fw != NULL) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302632 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2633 "%s: Pushing FW onto adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302634 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2635 ioc->cached_fw, CAN_SLEEP)) < 0) {
2636 printk(MYIOC_s_WARN_FMT
2637 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002638 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 }
2640 }
2641
Kashyap, Desai71278192009-05-29 16:53:14 +05302642 /*
2643 * Put the controller into ready state (if its not already)
2644 */
2645 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY) {
2646 if (!SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET,
2647 CAN_SLEEP)) {
2648 if (mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_READY)
2649 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit "
2650 "reset failed to put ioc in ready state!\n",
2651 ioc->name, __func__);
2652 } else
2653 printk(MYIOC_s_ERR_FMT "%s: IOC msg unit reset "
2654 "failed!\n", ioc->name, __func__);
2655 }
2656
2657
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 /* Disable adapter interrupts! */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302659 synchronize_irq(ioc->pcidev->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2661 ioc->active = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302662
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 /* Clear any lingering interrupt */
2664 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302665 CHIPREG_READ32(&ioc->chip->IntStatus);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666
2667 if (ioc->alloc != NULL) {
2668 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002669 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2670 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 pci_free_consistent(ioc->pcidev, sz,
2672 ioc->alloc, ioc->alloc_dma);
2673 ioc->reply_frames = NULL;
2674 ioc->req_frames = NULL;
2675 ioc->alloc = NULL;
2676 ioc->alloc_total -= sz;
2677 }
2678
2679 if (ioc->sense_buf_pool != NULL) {
2680 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2681 pci_free_consistent(ioc->pcidev, sz,
2682 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2683 ioc->sense_buf_pool = NULL;
2684 ioc->alloc_total -= sz;
2685 }
2686
2687 if (ioc->events != NULL){
2688 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2689 kfree(ioc->events);
2690 ioc->events = NULL;
2691 ioc->alloc_total -= sz;
2692 }
2693
Prakash, Sathya984621b2008-01-11 14:42:17 +05302694 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002696 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002697 mpt_inactive_raid_list_free(ioc);
2698 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002699 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002700 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002701 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702
2703 if (ioc->spi_data.pIocPg4 != NULL) {
2704 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302705 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 ioc->spi_data.pIocPg4,
2707 ioc->spi_data.IocPg4_dma);
2708 ioc->spi_data.pIocPg4 = NULL;
2709 ioc->alloc_total -= sz;
2710 }
2711
2712 if (ioc->ReqToChain != NULL) {
2713 kfree(ioc->ReqToChain);
2714 kfree(ioc->RequestNB);
2715 ioc->ReqToChain = NULL;
2716 }
2717
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002718 kfree(ioc->ChainToChain);
2719 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002720
2721 if (ioc->HostPageBuffer != NULL) {
2722 if((ret = mpt_host_page_access_control(ioc,
2723 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002724 printk(MYIOC_s_ERR_FMT
Kashyap, Desai2f187862009-05-29 16:52:37 +05302725 ": %s: host page buffers free failed (%d)!\n",
2726 ioc->name, __func__, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002727 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302728 dexitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2729 "HostPageBuffer free @ %p, sz=%d bytes\n",
2730 ioc->name, ioc->HostPageBuffer,
2731 ioc->HostPageBuffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002732 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002733 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002734 ioc->HostPageBuffer = NULL;
2735 ioc->HostPageBuffer_sz = 0;
2736 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2737 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738
Kashyap, Desai2f187862009-05-29 16:52:37 +05302739 pci_set_drvdata(ioc->pcidev, NULL);
2740}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002742/**
2743 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 * @ioc: Pointer to MPT adapter structure
2745 *
2746 * This routine unregisters h/w resources and frees all alloc'd memory
2747 * associated with a MPT adapter structure.
2748 */
2749static void
2750mpt_adapter_dispose(MPT_ADAPTER *ioc)
2751{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002752 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002754 if (ioc == NULL)
2755 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002757 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002759 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002761 if (ioc->pci_irq != -1) {
2762 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302763 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002764 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002765 ioc->pci_irq = -1;
2766 }
2767
2768 if (ioc->memmap != NULL) {
2769 iounmap(ioc->memmap);
2770 ioc->memmap = NULL;
2771 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302773 pci_disable_device(ioc->pcidev);
2774 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2775
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002777 if (ioc->mtrr_reg > 0) {
2778 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002779 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002780 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781#endif
2782
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002783 /* Zap the adapter lookup ptr! */
2784 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002786 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002787 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2788 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002789
2790 if (ioc->alt_ioc)
2791 ioc->alt_ioc->alt_ioc = NULL;
2792
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002793 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794}
2795
2796/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002797/**
2798 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 * @ioc: Pointer to MPT adapter structure
2800 */
2801static void
2802MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2803{
2804 int i = 0;
2805
2806 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302807 if (ioc->prod_name)
2808 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 printk("Capabilities={");
2810
2811 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2812 printk("Initiator");
2813 i++;
2814 }
2815
2816 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2817 printk("%sTarget", i ? "," : "");
2818 i++;
2819 }
2820
2821 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2822 printk("%sLAN", i ? "," : "");
2823 i++;
2824 }
2825
2826#if 0
2827 /*
2828 * This would probably evoke more questions than it's worth
2829 */
2830 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2831 printk("%sLogBusAddr", i ? "," : "");
2832 i++;
2833 }
2834#endif
2835
2836 printk("}\n");
2837}
2838
2839/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002840/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2842 * @ioc: Pointer to MPT_ADAPTER structure
2843 * @force: Force hard KickStart of IOC
2844 * @sleepFlag: Specifies whether the process can sleep
2845 *
2846 * Returns:
2847 * 1 - DIAG reset and READY
2848 * 0 - READY initially OR soft reset and READY
2849 * -1 - Any failure on KickStart
2850 * -2 - Msg Unit Reset Failed
2851 * -3 - IO Unit Reset Failed
2852 * -4 - IOC owned by a PEER
2853 */
2854static int
2855MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2856{
2857 u32 ioc_state;
2858 int statefault = 0;
2859 int cntdn;
2860 int hard_reset_done = 0;
2861 int r;
2862 int ii;
2863 int whoinit;
2864
2865 /* Get current [raw] IOC state */
2866 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002867 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868
2869 /*
2870 * Check to see if IOC got left/stuck in doorbell handshake
2871 * grip of death. If so, hard reset the IOC.
2872 */
2873 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2874 statefault = 1;
2875 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2876 ioc->name);
2877 }
2878
2879 /* Is it already READY? */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302880 if (!statefault &&
2881 ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)) {
2882 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2883 "IOC is in READY state\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 return 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302885 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886
2887 /*
2888 * Check to see if IOC is in FAULT state.
2889 */
2890 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2891 statefault = 2;
2892 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002893 ioc->name);
2894 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2895 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 }
2897
2898 /*
2899 * Hmmm... Did it get left operational?
2900 */
2901 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302902 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 ioc->name));
2904
2905 /* Check WhoInit.
2906 * If PCI Peer, exit.
2907 * Else, if no fault conditions are present, issue a MessageUnitReset
2908 * Else, fall through to KickStart case
2909 */
2910 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002911 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2912 "whoinit 0x%x statefault %d force %d\n",
2913 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 if (whoinit == MPI_WHOINIT_PCI_PEER)
2915 return -4;
2916 else {
2917 if ((statefault == 0 ) && (force == 0)) {
2918 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2919 return 0;
2920 }
2921 statefault = 3;
2922 }
2923 }
2924
2925 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2926 if (hard_reset_done < 0)
2927 return -1;
2928
2929 /*
2930 * Loop here waiting for IOC to come READY.
2931 */
2932 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002933 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934
2935 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2936 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2937 /*
2938 * BIOS or previous driver load left IOC in OP state.
2939 * Reset messaging FIFOs.
2940 */
2941 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2942 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2943 return -2;
2944 }
2945 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2946 /*
2947 * Something is wrong. Try to get IOC back
2948 * to a known state.
2949 */
2950 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2951 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2952 return -3;
2953 }
2954 }
2955
2956 ii++; cntdn--;
2957 if (!cntdn) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302958 printk(MYIOC_s_ERR_FMT
2959 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
2960 ioc->name, ioc_state, (int)((ii+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 return -ETIME;
2962 }
2963
2964 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002965 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 } else {
2967 mdelay (1); /* 1 msec delay */
2968 }
2969
2970 }
2971
2972 if (statefault < 3) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302973 printk(MYIOC_s_INFO_FMT "Recovered from %s\n", ioc->name,
2974 statefault == 1 ? "stuck handshake" : "IOC FAULT");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 }
2976
2977 return hard_reset_done;
2978}
2979
2980/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002981/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 * mpt_GetIocState - Get the current state of a MPT adapter.
2983 * @ioc: Pointer to MPT_ADAPTER structure
2984 * @cooked: Request raw or cooked IOC state
2985 *
2986 * Returns all IOC Doorbell register bits if cooked==0, else just the
2987 * Doorbell bits in MPI_IOC_STATE_MASK.
2988 */
2989u32
2990mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2991{
2992 u32 s, sc;
2993
2994 /* Get! */
2995 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 sc = s & MPI_IOC_STATE_MASK;
2997
2998 /* Save! */
2999 ioc->last_state = sc;
3000
3001 return cooked ? sc : s;
3002}
3003
3004/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003005/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 * GetIocFacts - Send IOCFacts request to MPT adapter.
3007 * @ioc: Pointer to MPT_ADAPTER structure
3008 * @sleepFlag: Specifies whether the process can sleep
3009 * @reason: If recovery, only update facts.
3010 *
3011 * Returns 0 for success, non-zero for failure.
3012 */
3013static int
3014GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
3015{
3016 IOCFacts_t get_facts;
3017 IOCFactsReply_t *facts;
3018 int r;
3019 int req_sz;
3020 int reply_sz;
3021 int sz;
3022 u32 status, vv;
3023 u8 shiftFactor=1;
3024
3025 /* IOC *must* NOT be in RESET state! */
3026 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303027 printk(KERN_ERR MYNAM
3028 ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
3029 ioc->name, ioc->last_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 return -44;
3031 }
3032
3033 facts = &ioc->facts;
3034
3035 /* Destination (reply area)... */
3036 reply_sz = sizeof(*facts);
3037 memset(facts, 0, reply_sz);
3038
3039 /* Request area (get_facts on the stack right now!) */
3040 req_sz = sizeof(get_facts);
3041 memset(&get_facts, 0, req_sz);
3042
3043 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
3044 /* Assert: All other get_facts fields are zero! */
3045
Prakash, Sathya436ace72007-07-24 15:42:08 +05303046 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003047 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 ioc->name, req_sz, reply_sz));
3049
3050 /* No non-zero fields in the get_facts request are greater than
3051 * 1 byte in size, so we can just fire it off as is.
3052 */
3053 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3054 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3055 if (r != 0)
3056 return r;
3057
3058 /*
3059 * Now byte swap (GRRR) the necessary fields before any further
3060 * inspection of reply contents.
3061 *
3062 * But need to do some sanity checks on MsgLength (byte) field
3063 * to make sure we don't zero IOC's req_sz!
3064 */
3065 /* Did we get a valid reply? */
3066 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3067 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3068 /*
3069 * If not been here, done that, save off first WhoInit value
3070 */
3071 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3072 ioc->FirstWhoInit = facts->WhoInit;
3073 }
3074
3075 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3076 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3077 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3078 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3079 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003080 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 /* CHECKME! IOCStatus, IOCLogInfo */
3082
3083 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3084 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3085
3086 /*
3087 * FC f/w version changed between 1.1 and 1.2
3088 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3089 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3090 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303091 if (facts->MsgVersion < MPI_VERSION_01_02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 /*
3093 * Handle old FC f/w style, convert to new...
3094 */
3095 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3096 facts->FWVersion.Word =
3097 ((oldv<<12) & 0xFF000000) |
3098 ((oldv<<8) & 0x000FFF00);
3099 } else
3100 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3101
3102 facts->ProductID = le16_to_cpu(facts->ProductID);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303103
Eric Mooreb506ade2007-01-29 09:45:37 -07003104 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3105 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3106 ioc->ir_firmware = 1;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303107
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 facts->CurrentHostMfaHighAddr =
3109 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3110 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3111 facts->CurrentSenseBufferHighAddr =
3112 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3113 facts->CurReplyFrameSize =
3114 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003115 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116
3117 /*
3118 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3119 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3120 * to 14 in MPI-1.01.0x.
3121 */
3122 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
Kashyap, Desai2f187862009-05-29 16:52:37 +05303123 facts->MsgVersion > MPI_VERSION_01_00) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3125 }
3126
3127 sz = facts->FWImageSize;
3128 if ( sz & 0x01 )
3129 sz += 1;
3130 if ( sz & 0x02 )
3131 sz += 2;
3132 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003133
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 if (!facts->RequestFrameSize) {
3135 /* Something is wrong! */
3136 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3137 ioc->name);
3138 return -55;
3139 }
3140
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003141 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 vv = ((63 / (sz * 4)) + 1) & 0x03;
3143 ioc->NB_for_64_byte_frame = vv;
3144 while ( sz )
3145 {
3146 shiftFactor++;
3147 sz = sz >> 1;
3148 }
3149 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303150 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003151 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3152 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003153
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3155 /*
3156 * Set values for this IOC's request & reply frame sizes,
3157 * and request & reply queue depths...
3158 */
3159 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3160 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3161 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3162 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3163
Prakash, Sathya436ace72007-07-24 15:42:08 +05303164 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303166 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 ioc->name, ioc->req_sz, ioc->req_depth));
3168
3169 /* Get port facts! */
3170 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3171 return r;
3172 }
3173 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003174 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3176 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3177 RequestFrameSize)/sizeof(u32)));
3178 return -66;
3179 }
3180
3181 return 0;
3182}
3183
3184/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003185/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 * GetPortFacts - Send PortFacts request to MPT adapter.
3187 * @ioc: Pointer to MPT_ADAPTER structure
3188 * @portnum: Port number
3189 * @sleepFlag: Specifies whether the process can sleep
3190 *
3191 * Returns 0 for success, non-zero for failure.
3192 */
3193static int
3194GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3195{
3196 PortFacts_t get_pfacts;
3197 PortFactsReply_t *pfacts;
3198 int ii;
3199 int req_sz;
3200 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003201 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202
3203 /* IOC *must* NOT be in RESET state! */
3204 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003205 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3206 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207 return -4;
3208 }
3209
3210 pfacts = &ioc->pfacts[portnum];
3211
3212 /* Destination (reply area)... */
3213 reply_sz = sizeof(*pfacts);
3214 memset(pfacts, 0, reply_sz);
3215
3216 /* Request area (get_pfacts on the stack right now!) */
3217 req_sz = sizeof(get_pfacts);
3218 memset(&get_pfacts, 0, req_sz);
3219
3220 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3221 get_pfacts.PortNumber = portnum;
3222 /* Assert: All other get_pfacts fields are zero! */
3223
Prakash, Sathya436ace72007-07-24 15:42:08 +05303224 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 ioc->name, portnum));
3226
3227 /* No non-zero fields in the get_pfacts request are greater than
3228 * 1 byte in size, so we can just fire it off as is.
3229 */
3230 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3231 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3232 if (ii != 0)
3233 return ii;
3234
3235 /* Did we get a valid reply? */
3236
3237 /* Now byte swap the necessary fields in the response. */
3238 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3239 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3240 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3241 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3242 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3243 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3244 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3245 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3246 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3247
Eric Moore793955f2007-01-29 09:42:20 -07003248 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3249 pfacts->MaxDevices;
3250 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3251 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3252
3253 /*
3254 * Place all the devices on channels
3255 *
3256 * (for debuging)
3257 */
3258 if (mpt_channel_mapping) {
3259 ioc->devices_per_bus = 1;
3260 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3261 }
3262
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 return 0;
3264}
3265
3266/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003267/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 * SendIocInit - Send IOCInit request to MPT adapter.
3269 * @ioc: Pointer to MPT_ADAPTER structure
3270 * @sleepFlag: Specifies whether the process can sleep
3271 *
3272 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3273 *
3274 * Returns 0 for success, non-zero for failure.
3275 */
3276static int
3277SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3278{
3279 IOCInit_t ioc_init;
3280 MPIDefaultReply_t init_reply;
3281 u32 state;
3282 int r;
3283 int count;
3284 int cntdn;
3285
3286 memset(&ioc_init, 0, sizeof(ioc_init));
3287 memset(&init_reply, 0, sizeof(init_reply));
3288
3289 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3290 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3291
3292 /* If we are in a recovery mode and we uploaded the FW image,
3293 * then this pointer is not NULL. Skip the upload a second time.
3294 * Set this flag if cached_fw set for either IOC.
3295 */
3296 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3297 ioc->upload_fw = 1;
3298 else
3299 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303300 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3302
Eric Moore793955f2007-01-29 09:42:20 -07003303 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3304 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303305
Prakash, Sathya436ace72007-07-24 15:42:08 +05303306 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003307 ioc->name, ioc->facts.MsgVersion));
3308 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3309 // set MsgVersion and HeaderVersion host driver was built with
3310 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3311 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003313 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3314 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3315 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3316 return -99;
3317 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3319
Kashyap, Desai2f187862009-05-29 16:52:37 +05303320 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 /* Save the upper 32-bits of the request
3322 * (reply) and sense buffers.
3323 */
3324 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3325 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3326 } else {
3327 /* Force 32-bit addressing */
3328 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3329 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3330 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003331
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3333 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003334 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3335 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336
Prakash, Sathya436ace72007-07-24 15:42:08 +05303337 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338 ioc->name, &ioc_init));
3339
3340 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3341 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003342 if (r != 0) {
3343 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003345 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346
3347 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003348 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 */
3350
Prakash, Sathya436ace72007-07-24 15:42:08 +05303351 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003353
3354 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3355 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003357 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358
3359 /* YIKES! SUPER IMPORTANT!!!
3360 * Poll IocState until _OPERATIONAL while IOC is doing
3361 * LoopInit and TargetDiscovery!
3362 */
3363 count = 0;
3364 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3365 state = mpt_GetIocState(ioc, 1);
3366 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3367 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003368 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 } else {
3370 mdelay(1);
3371 }
3372
3373 if (!cntdn) {
3374 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3375 ioc->name, (int)((count+5)/HZ));
3376 return -9;
3377 }
3378
3379 state = mpt_GetIocState(ioc, 1);
3380 count++;
3381 }
Eric Moore29dd3602007-09-14 18:46:51 -06003382 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 ioc->name, count));
3384
Eric Mooreba856d32006-07-11 17:34:01 -06003385 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 return r;
3387}
3388
3389/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003390/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 * SendPortEnable - Send PortEnable request to MPT adapter port.
3392 * @ioc: Pointer to MPT_ADAPTER structure
3393 * @portnum: Port number to enable
3394 * @sleepFlag: Specifies whether the process can sleep
3395 *
3396 * Send PortEnable to bring IOC to OPERATIONAL state.
3397 *
3398 * Returns 0 for success, non-zero for failure.
3399 */
3400static int
3401SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3402{
3403 PortEnable_t port_enable;
3404 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003405 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 int req_sz;
3407 int reply_sz;
3408
3409 /* Destination... */
3410 reply_sz = sizeof(MPIDefaultReply_t);
3411 memset(&reply_buf, 0, reply_sz);
3412
3413 req_sz = sizeof(PortEnable_t);
3414 memset(&port_enable, 0, req_sz);
3415
3416 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3417 port_enable.PortNumber = portnum;
3418/* port_enable.ChainOffset = 0; */
3419/* port_enable.MsgFlags = 0; */
3420/* port_enable.MsgContext = 0; */
3421
Prakash, Sathya436ace72007-07-24 15:42:08 +05303422 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 ioc->name, portnum, &port_enable));
3424
3425 /* RAID FW may take a long time to enable
3426 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003427 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003428 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3429 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3430 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003431 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003432 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3433 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3434 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003436 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437}
3438
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003439/**
3440 * mpt_alloc_fw_memory - allocate firmware memory
3441 * @ioc: Pointer to MPT_ADAPTER structure
3442 * @size: total FW bytes
3443 *
3444 * If memory has already been allocated, the same (cached) value
3445 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303446 *
3447 * Return 0 if successfull, or non-zero for failure
3448 **/
3449int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3451{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303452 int rc;
3453
3454 if (ioc->cached_fw) {
3455 rc = 0; /* use already allocated memory */
3456 goto out;
3457 }
3458 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3460 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303461 rc = 0;
3462 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303464 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3465 if (!ioc->cached_fw) {
3466 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3467 ioc->name);
3468 rc = -1;
3469 } else {
3470 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3471 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3472 ioc->alloc_total += size;
3473 rc = 0;
3474 }
3475 out:
3476 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303478
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003479/**
3480 * mpt_free_fw_memory - free firmware memory
3481 * @ioc: Pointer to MPT_ADAPTER structure
3482 *
3483 * If alt_img is NULL, delete from ioc structure.
3484 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303485 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486void
3487mpt_free_fw_memory(MPT_ADAPTER *ioc)
3488{
3489 int sz;
3490
Prakash, Sathya984621b2008-01-11 14:42:17 +05303491 if (!ioc->cached_fw)
3492 return;
3493
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303495 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3496 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003497 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303498 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500}
3501
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003503/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3505 * @ioc: Pointer to MPT_ADAPTER structure
3506 * @sleepFlag: Specifies whether the process can sleep
3507 *
3508 * Returns 0 for success, >0 for handshake failure
3509 * <0 for fw upload failure.
3510 *
3511 * Remark: If bound IOC and a successful FWUpload was performed
3512 * on the bound IOC, the second image is discarded
3513 * and memory is free'd. Both channels must upload to prevent
3514 * IOC from running in degraded mode.
3515 */
3516static int
3517mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3518{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519 u8 reply[sizeof(FWUploadReply_t)];
3520 FWUpload_t *prequest;
3521 FWUploadReply_t *preply;
3522 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 u32 flagsLength;
3524 int ii, sz, reply_sz;
3525 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303526 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 /* If the image size is 0, we are done.
3528 */
3529 if ((sz = ioc->facts.FWImageSize) == 0)
3530 return 0;
3531
Prakash, Sathya984621b2008-01-11 14:42:17 +05303532 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3533 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534
Eric Moore29dd3602007-09-14 18:46:51 -06003535 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3536 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003537
Eric Moorebc6e0892007-09-29 10:16:28 -06003538 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3539 kzalloc(ioc->req_sz, GFP_KERNEL);
3540 if (!prequest) {
3541 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3542 "while allocating memory \n", ioc->name));
3543 mpt_free_fw_memory(ioc);
3544 return -ENOMEM;
3545 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546
Eric Moorebc6e0892007-09-29 10:16:28 -06003547 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548
3549 reply_sz = sizeof(reply);
3550 memset(preply, 0, reply_sz);
3551
3552 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3553 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3554
3555 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3556 ptcsge->DetailsLength = 12;
3557 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3558 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003559 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303562 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3563 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3564 ioc->SGE_size;
3565 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3566 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3567 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003568 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303570 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3571 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572
Kashyap, Desai2f187862009-05-29 16:52:37 +05303573 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Upload completed "
3574 "rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575
3576 cmdStatus = -EFAULT;
3577 if (ii == 0) {
3578 /* Handshake transfer was complete and successful.
3579 * Check the Reply Frame.
3580 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303581 int status;
3582 status = le16_to_cpu(preply->IOCStatus) &
3583 MPI_IOCSTATUS_MASK;
3584 if (status == MPI_IOCSTATUS_SUCCESS &&
3585 ioc->facts.FWImageSize ==
3586 le32_to_cpu(preply->ActualImageSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587 cmdStatus = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303589 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 ioc->name, cmdStatus));
3591
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003592
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 if (cmdStatus) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303594 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed, "
3595 "freeing image \n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 mpt_free_fw_memory(ioc);
3597 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003598 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599
3600 return cmdStatus;
3601}
3602
3603/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003604/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 * mpt_downloadboot - DownloadBoot code
3606 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003607 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 * @sleepFlag: Specifies whether the process can sleep
3609 *
3610 * FwDownloadBoot requires Programmed IO access.
3611 *
3612 * Returns 0 for success
3613 * -1 FW Image size is 0
3614 * -2 No valid cached_fw Pointer
3615 * <0 for fw upload failure.
3616 */
3617static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003618mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 MpiExtImageHeader_t *pExtImage;
3621 u32 fwSize;
3622 u32 diag0val;
3623 int count;
3624 u32 *ptrFw;
3625 u32 diagRwData;
3626 u32 nextImage;
3627 u32 load_addr;
3628 u32 ioc_state=0;
3629
Prakash, Sathya436ace72007-07-24 15:42:08 +05303630 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003631 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003632
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3634 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3635 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3636 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3637 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3638 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3639
3640 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3641
3642 /* wait 1 msec */
3643 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003644 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 } else {
3646 mdelay (1);
3647 }
3648
3649 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3650 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3651
3652 for (count = 0; count < 30; count ++) {
3653 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3654 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303655 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656 ioc->name, count));
3657 break;
3658 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003659 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003661 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003663 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 }
3665 }
3666
3667 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303668 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003669 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 ioc->name, diag0val));
3671 return -3;
3672 }
3673
3674 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3675 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3676 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3677 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3678 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3679 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3680
3681 /* Set the DiagRwEn and Disable ARM bits */
3682 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3683
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 fwSize = (pFwHeader->ImageSize + 3)/4;
3685 ptrFw = (u32 *) pFwHeader;
3686
3687 /* Write the LoadStartAddress to the DiagRw Address Register
3688 * using Programmed IO
3689 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003690 if (ioc->errata_flag_1064)
3691 pci_enable_io_access(ioc->pcidev);
3692
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303694 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 ioc->name, pFwHeader->LoadStartAddress));
3696
Prakash, Sathya436ace72007-07-24 15:42:08 +05303697 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 ioc->name, fwSize*4, ptrFw));
3699 while (fwSize--) {
3700 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3701 }
3702
3703 nextImage = pFwHeader->NextImageHeaderOffset;
3704 while (nextImage) {
3705 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3706
3707 load_addr = pExtImage->LoadStartAddress;
3708
3709 fwSize = (pExtImage->ImageSize + 3) >> 2;
3710 ptrFw = (u32 *)pExtImage;
3711
Prakash, Sathya436ace72007-07-24 15:42:08 +05303712 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 +02003713 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3715
3716 while (fwSize--) {
3717 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3718 }
3719 nextImage = pExtImage->NextImageHeaderOffset;
3720 }
3721
3722 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303723 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3725
3726 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303727 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3729
3730 /* Clear the internal flash bad bit - autoincrementing register,
3731 * so must do two writes.
3732 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003733 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003734 /*
3735 * 1030 and 1035 H/W errata, workaround to access
3736 * the ClearFlashBadSignatureBit
3737 */
3738 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3739 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3740 diagRwData |= 0x40000000;
3741 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3742 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3743
3744 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3745 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3746 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3747 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3748
3749 /* wait 1 msec */
3750 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003751 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003752 } else {
3753 mdelay (1);
3754 }
3755 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003757 if (ioc->errata_flag_1064)
3758 pci_disable_io_access(ioc->pcidev);
3759
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303761 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003762 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003764 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303765 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766 ioc->name, diag0val));
3767 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3768
3769 /* Write 0xFF to reset the sequencer */
3770 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3771
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003772 if (ioc->bus_type == SAS) {
3773 ioc_state = mpt_GetIocState(ioc, 0);
3774 if ( (GetIocFacts(ioc, sleepFlag,
3775 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303776 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003777 ioc->name, ioc_state));
3778 return -EFAULT;
3779 }
3780 }
3781
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 for (count=0; count<HZ*20; count++) {
3783 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303784 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3785 "downloadboot successful! (count=%d) IocState=%x\n",
3786 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003787 if (ioc->bus_type == SAS) {
3788 return 0;
3789 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303791 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3792 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 ioc->name));
3794 return -EFAULT;
3795 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303796 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3797 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798 ioc->name));
3799 return 0;
3800 }
3801 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003802 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 } else {
3804 mdelay (10);
3805 }
3806 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303807 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3808 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809 return -EFAULT;
3810}
3811
3812/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003813/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814 * KickStart - Perform hard reset of MPT adapter.
3815 * @ioc: Pointer to MPT_ADAPTER structure
3816 * @force: Force hard reset
3817 * @sleepFlag: Specifies whether the process can sleep
3818 *
3819 * This routine places MPT adapter in diagnostic mode via the
3820 * WriteSequence register, and then performs a hard reset of adapter
3821 * via the Diagnostic register.
3822 *
3823 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3824 * or NO_SLEEP (interrupt thread, use mdelay)
3825 * force - 1 if doorbell active, board fault state
3826 * board operational, IOC_RECOVERY or
3827 * IOC_BRINGUP and there is an alt_ioc.
3828 * 0 else
3829 *
3830 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003831 * 1 - hard reset, READY
3832 * 0 - no reset due to History bit, READY
3833 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834 * OR reset but failed to come READY
3835 * -2 - no reset, could not enter DIAG mode
3836 * -3 - reset but bad FW bit
3837 */
3838static int
3839KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3840{
3841 int hard_reset_done = 0;
3842 u32 ioc_state=0;
3843 int cnt,cntdn;
3844
Eric Moore29dd3602007-09-14 18:46:51 -06003845 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003846 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003847 /* Always issue a Msg Unit Reset first. This will clear some
3848 * SCSI bus hang conditions.
3849 */
3850 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3851
3852 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003853 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854 } else {
3855 mdelay (1000);
3856 }
3857 }
3858
3859 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3860 if (hard_reset_done < 0)
3861 return hard_reset_done;
3862
Prakash, Sathya436ace72007-07-24 15:42:08 +05303863 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003864 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865
3866 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3867 for (cnt=0; cnt<cntdn; cnt++) {
3868 ioc_state = mpt_GetIocState(ioc, 1);
3869 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303870 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871 ioc->name, cnt));
3872 return hard_reset_done;
3873 }
3874 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003875 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876 } else {
3877 mdelay (10);
3878 }
3879 }
3880
Eric Moore29dd3602007-09-14 18:46:51 -06003881 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3882 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883 return -1;
3884}
3885
3886/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003887/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 * mpt_diag_reset - Perform hard reset of the adapter.
3889 * @ioc: Pointer to MPT_ADAPTER structure
3890 * @ignore: Set if to honor and clear to ignore
3891 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003892 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 * else set to NO_SLEEP (use mdelay instead)
3894 *
3895 * This routine places the adapter in diagnostic mode via the
3896 * WriteSequence register and then performs a hard reset of adapter
3897 * via the Diagnostic register. Adapter should be in ready state
3898 * upon successful completion.
3899 *
3900 * Returns: 1 hard reset successful
3901 * 0 no reset performed because reset history bit set
3902 * -2 enabling diagnostic mode failed
3903 * -3 diagnostic reset failed
3904 */
3905static int
3906mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3907{
3908 u32 diag0val;
3909 u32 doorbell;
3910 int hard_reset_done = 0;
3911 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303913 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Kashyap, Desaid1306912009-08-05 12:53:51 +05303914 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915
Eric Moorecd2c6192007-01-29 09:47:47 -07003916 /* Clear any existing interrupts */
3917 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3918
Eric Moore87cf8982006-06-27 16:09:26 -06003919 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05303920
3921 if (!ignore)
3922 return 0;
3923
Prakash, Sathya436ace72007-07-24 15:42:08 +05303924 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003925 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003926 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3927 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3928 if (sleepFlag == CAN_SLEEP)
3929 msleep(1);
3930 else
3931 mdelay(1);
3932
Kashyap, Desaid1306912009-08-05 12:53:51 +05303933 /*
3934 * Call each currently registered protocol IOC reset handler
3935 * with pre-reset indication.
3936 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3937 * MptResetHandlers[] registered yet.
3938 */
3939 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3940 if (MptResetHandlers[cb_idx])
3941 (*(MptResetHandlers[cb_idx]))(ioc,
3942 MPT_IOC_PRE_RESET);
3943 }
3944
Eric Moore87cf8982006-06-27 16:09:26 -06003945 for (count = 0; count < 60; count ++) {
3946 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3947 doorbell &= MPI_IOC_STATE_MASK;
3948
Prakash, Sathya436ace72007-07-24 15:42:08 +05303949 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003950 "looking for READY STATE: doorbell=%x"
3951 " count=%d\n",
3952 ioc->name, doorbell, count));
Kashyap, Desai2f187862009-05-29 16:52:37 +05303953
Eric Moore87cf8982006-06-27 16:09:26 -06003954 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003955 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003956 }
3957
3958 /* wait 1 sec */
3959 if (sleepFlag == CAN_SLEEP)
3960 msleep(1000);
3961 else
3962 mdelay(1000);
3963 }
3964 return -1;
3965 }
3966
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 /* Use "Diagnostic reset" method! (only thing available!) */
3968 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3969
Prakash, Sathya436ace72007-07-24 15:42:08 +05303970 if (ioc->debug_level & MPT_DEBUG) {
3971 if (ioc->alt_ioc)
3972 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3973 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303975 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976
3977 /* Do the reset if we are told to ignore the reset history
3978 * or if the reset history is 0
3979 */
3980 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3981 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3982 /* Write magic sequence to WriteSequence register
3983 * Loop until in diagnostic mode
3984 */
3985 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3986 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3987 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3988 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3989 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3990 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3991
3992 /* wait 100 msec */
3993 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003994 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 } else {
3996 mdelay (100);
3997 }
3998
3999 count++;
4000 if (count > 20) {
4001 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4002 ioc->name, diag0val);
4003 return -2;
4004
4005 }
4006
4007 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4008
Prakash, Sathya436ace72007-07-24 15:42:08 +05304009 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 ioc->name, diag0val));
4011 }
4012
Prakash, Sathya436ace72007-07-24 15:42:08 +05304013 if (ioc->debug_level & MPT_DEBUG) {
4014 if (ioc->alt_ioc)
4015 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4016 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304018 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 /*
4020 * Disable the ARM (Bug fix)
4021 *
4022 */
4023 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004024 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025
4026 /*
4027 * Now hit the reset bit in the Diagnostic register
4028 * (THE BIG HAMMER!) (Clears DRWE bit).
4029 */
4030 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
4031 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304032 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 ioc->name));
4034
4035 /*
4036 * Call each currently registered protocol IOC reset handler
4037 * with pre-reset indication.
4038 * NOTE: If we're doing _IOC_BRINGUP, there can be no
4039 * MptResetHandlers[] registered yet.
4040 */
Kashyap, Desaid1306912009-08-05 12:53:51 +05304041 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
4042 if (MptResetHandlers[cb_idx]) {
4043 mpt_signal_reset(cb_idx,
4044 ioc, MPT_IOC_PRE_RESET);
4045 if (ioc->alt_ioc) {
4046 mpt_signal_reset(cb_idx,
4047 ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 }
4049 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 }
4051
Eric Moore0ccdb002006-07-11 17:33:13 -06004052 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304053 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06004054 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05304055 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
4056 else
4057 cached_fw = NULL;
4058 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059 /* If the DownloadBoot operation fails, the
4060 * IOC will be left unusable. This is a fatal error
4061 * case. _diag_reset will return < 0
4062 */
4063 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304064 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4066 break;
4067 }
4068
Prakash, Sathya436ace72007-07-24 15:42:08 +05304069 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304070 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071 /* wait 1 sec */
4072 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004073 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074 } else {
4075 mdelay (1000);
4076 }
4077 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304078 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004079 printk(MYIOC_s_WARN_FMT
4080 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081 }
4082
4083 } else {
4084 /* Wait for FW to reload and for board
4085 * to go to the READY state.
4086 * Maximum wait is 60 seconds.
4087 * If fail, no error will check again
4088 * with calling program.
4089 */
4090 for (count = 0; count < 60; count ++) {
4091 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4092 doorbell &= MPI_IOC_STATE_MASK;
4093
Kashyap, Desai2f187862009-05-29 16:52:37 +05304094 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4095 "looking for READY STATE: doorbell=%x"
4096 " count=%d\n", ioc->name, doorbell, count));
4097
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098 if (doorbell == MPI_IOC_STATE_READY) {
4099 break;
4100 }
4101
4102 /* wait 1 sec */
4103 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004104 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105 } else {
4106 mdelay (1000);
4107 }
4108 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05304109
4110 if (doorbell != MPI_IOC_STATE_READY)
4111 printk(MYIOC_s_ERR_FMT "Failed to come READY "
4112 "after reset! IocState=%x", ioc->name,
4113 doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114 }
4115 }
4116
4117 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304118 if (ioc->debug_level & MPT_DEBUG) {
4119 if (ioc->alt_ioc)
4120 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4121 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4122 ioc->name, diag0val, diag1val));
4123 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124
4125 /* Clear RESET_HISTORY bit! Place board in the
4126 * diagnostic mode to update the diag register.
4127 */
4128 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4129 count = 0;
4130 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4131 /* Write magic sequence to WriteSequence register
4132 * Loop until in diagnostic mode
4133 */
4134 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4135 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4136 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4137 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4138 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4139 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4140
4141 /* wait 100 msec */
4142 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004143 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144 } else {
4145 mdelay (100);
4146 }
4147
4148 count++;
4149 if (count > 20) {
4150 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4151 ioc->name, diag0val);
4152 break;
4153 }
4154 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4155 }
4156 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4157 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4158 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4159 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4160 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4161 ioc->name);
4162 }
4163
4164 /* Disable Diagnostic Mode
4165 */
4166 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4167
4168 /* Check FW reload status flags.
4169 */
4170 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4171 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4172 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4173 ioc->name, diag0val);
4174 return -3;
4175 }
4176
Prakash, Sathya436ace72007-07-24 15:42:08 +05304177 if (ioc->debug_level & MPT_DEBUG) {
4178 if (ioc->alt_ioc)
4179 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4180 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183
4184 /*
4185 * Reset flag that says we've enabled event notification
4186 */
4187 ioc->facts.EventState = 0;
4188
4189 if (ioc->alt_ioc)
4190 ioc->alt_ioc->facts.EventState = 0;
4191
4192 return hard_reset_done;
4193}
4194
4195/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004196/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197 * SendIocReset - Send IOCReset request to MPT adapter.
4198 * @ioc: Pointer to MPT_ADAPTER structure
4199 * @reset_type: reset type, expected values are
4200 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004201 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202 *
4203 * Send IOCReset request to the MPT adapter.
4204 *
4205 * Returns 0 for success, non-zero for failure.
4206 */
4207static int
4208SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4209{
4210 int r;
4211 u32 state;
4212 int cntdn, count;
4213
Prakash, Sathya436ace72007-07-24 15:42:08 +05304214 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 ioc->name, reset_type));
4216 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4217 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4218 return r;
4219
4220 /* FW ACK'd request, wait for READY state
4221 */
4222 count = 0;
4223 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4224
4225 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4226 cntdn--;
4227 count++;
4228 if (!cntdn) {
4229 if (sleepFlag != CAN_SLEEP)
4230 count *= 10;
4231
Kashyap, Desai2f187862009-05-29 16:52:37 +05304232 printk(MYIOC_s_ERR_FMT
4233 "Wait IOC_READY state (0x%x) timeout(%d)!\n",
4234 ioc->name, state, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235 return -ETIME;
4236 }
4237
4238 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004239 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 } else {
4241 mdelay (1); /* 1 msec delay */
4242 }
4243 }
4244
4245 /* TODO!
4246 * Cleanup all event stuff for this IOC; re-issue EventNotification
4247 * request if needed.
4248 */
4249 if (ioc->facts.Function)
4250 ioc->facts.EventState = 0;
4251
4252 return 0;
4253}
4254
4255/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004256/**
4257 * initChainBuffers - Allocate memory for and initialize chain buffers
4258 * @ioc: Pointer to MPT_ADAPTER structure
4259 *
4260 * Allocates memory for and initializes chain buffers,
4261 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262 */
4263static int
4264initChainBuffers(MPT_ADAPTER *ioc)
4265{
4266 u8 *mem;
4267 int sz, ii, num_chain;
4268 int scale, num_sge, numSGE;
4269
4270 /* ReqToChain size must equal the req_depth
4271 * index = req_idx
4272 */
4273 if (ioc->ReqToChain == NULL) {
4274 sz = ioc->req_depth * sizeof(int);
4275 mem = kmalloc(sz, GFP_ATOMIC);
4276 if (mem == NULL)
4277 return -1;
4278
4279 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304280 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 ioc->name, mem, sz));
4282 mem = kmalloc(sz, GFP_ATOMIC);
4283 if (mem == NULL)
4284 return -1;
4285
4286 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304287 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288 ioc->name, mem, sz));
4289 }
4290 for (ii = 0; ii < ioc->req_depth; ii++) {
4291 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4292 }
4293
4294 /* ChainToChain size must equal the total number
4295 * of chain buffers to be allocated.
4296 * index = chain_idx
4297 *
4298 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004299 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 *
4301 * num_sge = num sge in request frame + last chain buffer
4302 * scale = num sge per chain buffer if no chain element
4303 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304304 scale = ioc->req_sz / ioc->SGE_size;
4305 if (ioc->sg_addr_size == sizeof(u64))
4306 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304308 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304310 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304312 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304314 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4315 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304317 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318 ioc->name, num_sge, numSGE));
4319
Kashyap, Desai2f187862009-05-29 16:52:37 +05304320 if (ioc->bus_type == FC) {
4321 if (numSGE > MPT_SCSI_FC_SG_DEPTH)
4322 numSGE = MPT_SCSI_FC_SG_DEPTH;
4323 } else {
4324 if (numSGE > MPT_SCSI_SG_DEPTH)
4325 numSGE = MPT_SCSI_SG_DEPTH;
4326 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327
4328 num_chain = 1;
4329 while (numSGE - num_sge > 0) {
4330 num_chain++;
4331 num_sge += (scale - 1);
4332 }
4333 num_chain++;
4334
Prakash, Sathya436ace72007-07-24 15:42:08 +05304335 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 ioc->name, numSGE, num_sge, num_chain));
4337
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004338 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339 num_chain *= MPT_SCSI_CAN_QUEUE;
Anatolij Gustschinf1053a72009-12-12 14:52:21 +01004340 else if (ioc->bus_type == SAS)
4341 num_chain *= MPT_SAS_CAN_QUEUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 else
4343 num_chain *= MPT_FC_CAN_QUEUE;
4344
4345 ioc->num_chain = num_chain;
4346
4347 sz = num_chain * sizeof(int);
4348 if (ioc->ChainToChain == NULL) {
4349 mem = kmalloc(sz, GFP_ATOMIC);
4350 if (mem == NULL)
4351 return -1;
4352
4353 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304354 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 ioc->name, mem, sz));
4356 } else {
4357 mem = (u8 *) ioc->ChainToChain;
4358 }
4359 memset(mem, 0xFF, sz);
4360 return num_chain;
4361}
4362
4363/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004364/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4366 * @ioc: Pointer to MPT_ADAPTER structure
4367 *
4368 * This routine allocates memory for the MPT reply and request frame
4369 * pools (if necessary), and primes the IOC reply FIFO with
4370 * reply frames.
4371 *
4372 * Returns 0 for success, non-zero for failure.
4373 */
4374static int
4375PrimeIocFifos(MPT_ADAPTER *ioc)
4376{
4377 MPT_FRAME_HDR *mf;
4378 unsigned long flags;
4379 dma_addr_t alloc_dma;
4380 u8 *mem;
4381 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304382 u64 dma_mask;
4383
4384 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385
4386 /* Prime reply FIFO... */
4387
4388 if (ioc->reply_frames == NULL) {
4389 if ( (num_chain = initChainBuffers(ioc)) < 0)
4390 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304391 /*
4392 * 1078 errata workaround for the 36GB limitation
4393 */
4394 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
Andrew Morton8e20ce92009-06-18 16:49:17 -07004395 ioc->dma_mask > DMA_BIT_MASK(35)) {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304396 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4397 && !pci_set_consistent_dma_mask(ioc->pcidev,
4398 DMA_BIT_MASK(32))) {
Andrew Morton8e20ce92009-06-18 16:49:17 -07004399 dma_mask = DMA_BIT_MASK(35);
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304400 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4401 "setting 35 bit addressing for "
4402 "Request/Reply/Chain and Sense Buffers\n",
4403 ioc->name));
4404 } else {
4405 /*Reseting DMA mask to 64 bit*/
4406 pci_set_dma_mask(ioc->pcidev,
4407 DMA_BIT_MASK(64));
4408 pci_set_consistent_dma_mask(ioc->pcidev,
4409 DMA_BIT_MASK(64));
4410
4411 printk(MYIOC_s_ERR_FMT
4412 "failed setting 35 bit addressing for "
4413 "Request/Reply/Chain and Sense Buffers\n",
4414 ioc->name);
4415 return -1;
4416 }
4417 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418
4419 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304420 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304422 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423 ioc->name, reply_sz, reply_sz));
4424
4425 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304426 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304428 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 ioc->name, sz, sz));
4430 total_size += sz;
4431
4432 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304433 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304435 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436 ioc->name, sz, sz, num_chain));
4437
4438 total_size += sz;
4439 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4440 if (mem == NULL) {
4441 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4442 ioc->name);
4443 goto out_fail;
4444 }
4445
Prakash, Sathya436ace72007-07-24 15:42:08 +05304446 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4448
4449 memset(mem, 0, total_size);
4450 ioc->alloc_total += total_size;
4451 ioc->alloc = mem;
4452 ioc->alloc_dma = alloc_dma;
4453 ioc->alloc_sz = total_size;
4454 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4455 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4456
Prakash, Sathya436ace72007-07-24 15:42:08 +05304457 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004458 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4459
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 alloc_dma += reply_sz;
4461 mem += reply_sz;
4462
4463 /* Request FIFO - WE manage this! */
4464
4465 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4466 ioc->req_frames_dma = alloc_dma;
4467
Prakash, Sathya436ace72007-07-24 15:42:08 +05304468 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469 ioc->name, mem, (void *)(ulong)alloc_dma));
4470
4471 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4472
4473#if defined(CONFIG_MTRR) && 0
4474 /*
4475 * Enable Write Combining MTRR for IOC's memory region.
4476 * (at least as much as we can; "size and base must be
4477 * multiples of 4 kiB"
4478 */
4479 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4480 sz,
4481 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304482 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 ioc->name, ioc->req_frames_dma, sz));
4484#endif
4485
4486 for (i = 0; i < ioc->req_depth; i++) {
4487 alloc_dma += ioc->req_sz;
4488 mem += ioc->req_sz;
4489 }
4490
4491 ioc->ChainBuffer = mem;
4492 ioc->ChainBufferDMA = alloc_dma;
4493
Prakash, Sathya436ace72007-07-24 15:42:08 +05304494 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4496
4497 /* Initialize the free chain Q.
4498 */
4499
4500 INIT_LIST_HEAD(&ioc->FreeChainQ);
4501
4502 /* Post the chain buffers to the FreeChainQ.
4503 */
4504 mem = (u8 *)ioc->ChainBuffer;
4505 for (i=0; i < num_chain; i++) {
4506 mf = (MPT_FRAME_HDR *) mem;
4507 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4508 mem += ioc->req_sz;
4509 }
4510
4511 /* Initialize Request frames linked list
4512 */
4513 alloc_dma = ioc->req_frames_dma;
4514 mem = (u8 *) ioc->req_frames;
4515
4516 spin_lock_irqsave(&ioc->FreeQlock, flags);
4517 INIT_LIST_HEAD(&ioc->FreeQ);
4518 for (i = 0; i < ioc->req_depth; i++) {
4519 mf = (MPT_FRAME_HDR *) mem;
4520
4521 /* Queue REQUESTs *internally*! */
4522 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4523
4524 mem += ioc->req_sz;
4525 }
4526 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4527
4528 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4529 ioc->sense_buf_pool =
4530 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4531 if (ioc->sense_buf_pool == NULL) {
4532 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4533 ioc->name);
4534 goto out_fail;
4535 }
4536
4537 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4538 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304539 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4541
4542 }
4543
4544 /* Post Reply frames to FIFO
4545 */
4546 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304547 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4549
4550 for (i = 0; i < ioc->reply_depth; i++) {
4551 /* Write each address to the IOC! */
4552 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4553 alloc_dma += ioc->reply_sz;
4554 }
4555
Andrew Morton8e20ce92009-06-18 16:49:17 -07004556 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304557 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4558 ioc->dma_mask))
4559 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4560 "restoring 64 bit addressing\n", ioc->name));
4561
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 return 0;
4563
4564out_fail:
Kashyap, Desai2f187862009-05-29 16:52:37 +05304565
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566 if (ioc->alloc != NULL) {
4567 sz = ioc->alloc_sz;
4568 pci_free_consistent(ioc->pcidev,
4569 sz,
4570 ioc->alloc, ioc->alloc_dma);
4571 ioc->reply_frames = NULL;
4572 ioc->req_frames = NULL;
4573 ioc->alloc_total -= sz;
4574 }
4575 if (ioc->sense_buf_pool != NULL) {
4576 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4577 pci_free_consistent(ioc->pcidev,
4578 sz,
4579 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4580 ioc->sense_buf_pool = NULL;
4581 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304582
Andrew Morton8e20ce92009-06-18 16:49:17 -07004583 if (dma_mask == DMA_BIT_MASK(35) && !pci_set_dma_mask(ioc->pcidev,
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304584 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4585 DMA_BIT_MASK(64)))
4586 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4587 "restoring 64 bit addressing\n", ioc->name));
4588
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 return -1;
4590}
4591
4592/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4593/**
4594 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4595 * from IOC via doorbell handshake method.
4596 * @ioc: Pointer to MPT_ADAPTER structure
4597 * @reqBytes: Size of the request in bytes
4598 * @req: Pointer to MPT request frame
4599 * @replyBytes: Expected size of the reply in bytes
4600 * @u16reply: Pointer to area where reply should be written
4601 * @maxwait: Max wait time for a reply (in seconds)
4602 * @sleepFlag: Specifies whether the process can sleep
4603 *
4604 * NOTES: It is the callers responsibility to byte-swap fields in the
4605 * request which are greater than 1 byte in size. It is also the
4606 * callers responsibility to byte-swap response fields which are
4607 * greater than 1 byte in size.
4608 *
4609 * Returns 0 for success, non-zero for failure.
4610 */
4611static int
4612mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004613 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614{
4615 MPIDefaultReply_t *mptReply;
4616 int failcnt = 0;
4617 int t;
4618
4619 /*
4620 * Get ready to cache a handshake reply
4621 */
4622 ioc->hs_reply_idx = 0;
4623 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4624 mptReply->MsgLength = 0;
4625
4626 /*
4627 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4628 * then tell IOC that we want to handshake a request of N words.
4629 * (WRITE u32val to Doorbell reg).
4630 */
4631 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4632 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4633 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4634 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4635
4636 /*
4637 * Wait for IOC's doorbell handshake int
4638 */
4639 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4640 failcnt++;
4641
Prakash, Sathya436ace72007-07-24 15:42:08 +05304642 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4644
4645 /* Read doorbell and check for active bit */
4646 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4647 return -1;
4648
4649 /*
4650 * Clear doorbell int (WRITE 0 to IntStatus reg),
4651 * then wait for IOC to ACKnowledge that it's ready for
4652 * our handshake request.
4653 */
4654 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4655 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4656 failcnt++;
4657
4658 if (!failcnt) {
4659 int ii;
4660 u8 *req_as_bytes = (u8 *) req;
4661
4662 /*
4663 * Stuff request words via doorbell handshake,
4664 * with ACK from IOC for each.
4665 */
4666 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4667 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4668 (req_as_bytes[(ii*4) + 1] << 8) |
4669 (req_as_bytes[(ii*4) + 2] << 16) |
4670 (req_as_bytes[(ii*4) + 3] << 24));
4671
4672 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4673 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4674 failcnt++;
4675 }
4676
Prakash, Sathya436ace72007-07-24 15:42:08 +05304677 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004678 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679
Prakash, Sathya436ace72007-07-24 15:42:08 +05304680 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4682
4683 /*
4684 * Wait for completion of doorbell handshake reply from the IOC
4685 */
4686 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4687 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004688
Prakash, Sathya436ace72007-07-24 15:42:08 +05304689 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4691
4692 /*
4693 * Copy out the cached reply...
4694 */
4695 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4696 u16reply[ii] = ioc->hs_reply[ii];
4697 } else {
4698 return -99;
4699 }
4700
4701 return -failcnt;
4702}
4703
4704/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004705/**
4706 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707 * @ioc: Pointer to MPT_ADAPTER structure
4708 * @howlong: How long to wait (in seconds)
4709 * @sleepFlag: Specifies whether the process can sleep
4710 *
4711 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004712 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4713 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714 *
4715 * Returns a negative value on failure, else wait loop count.
4716 */
4717static int
4718WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4719{
4720 int cntdn;
4721 int count = 0;
4722 u32 intstat=0;
4723
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004724 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725
4726 if (sleepFlag == CAN_SLEEP) {
4727 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004728 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4730 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4731 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 count++;
4733 }
4734 } else {
4735 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004736 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4738 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4739 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740 count++;
4741 }
4742 }
4743
4744 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304745 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746 ioc->name, count));
4747 return count;
4748 }
4749
4750 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4751 ioc->name, count, intstat);
4752 return -1;
4753}
4754
4755/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004756/**
4757 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 * @ioc: Pointer to MPT_ADAPTER structure
4759 * @howlong: How long to wait (in seconds)
4760 * @sleepFlag: Specifies whether the process can sleep
4761 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004762 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4763 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764 *
4765 * Returns a negative value on failure, else wait loop count.
4766 */
4767static int
4768WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4769{
4770 int cntdn;
4771 int count = 0;
4772 u32 intstat=0;
4773
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004774 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 if (sleepFlag == CAN_SLEEP) {
4776 while (--cntdn) {
4777 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4778 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4779 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004780 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 count++;
4782 }
4783 } else {
4784 while (--cntdn) {
4785 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4786 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4787 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004788 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 count++;
4790 }
4791 }
4792
4793 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304794 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795 ioc->name, count, howlong));
4796 return count;
4797 }
4798
4799 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4800 ioc->name, count, intstat);
4801 return -1;
4802}
4803
4804/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004805/**
4806 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 * @ioc: Pointer to MPT_ADAPTER structure
4808 * @howlong: How long to wait (in seconds)
4809 * @sleepFlag: Specifies whether the process can sleep
4810 *
4811 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4812 * Reply is cached to IOC private area large enough to hold a maximum
4813 * of 128 bytes of reply data.
4814 *
4815 * Returns a negative value on failure, else size of reply in WORDS.
4816 */
4817static int
4818WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4819{
4820 int u16cnt = 0;
4821 int failcnt = 0;
4822 int t;
4823 u16 *hs_reply = ioc->hs_reply;
4824 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4825 u16 hword;
4826
4827 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4828
4829 /*
4830 * Get first two u16's so we can look at IOC's intended reply MsgLength
4831 */
4832 u16cnt=0;
4833 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4834 failcnt++;
4835 } else {
4836 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4837 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4838 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4839 failcnt++;
4840 else {
4841 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4842 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4843 }
4844 }
4845
Prakash, Sathya436ace72007-07-24 15:42:08 +05304846 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004847 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4849
4850 /*
4851 * If no error (and IOC said MsgLength is > 0), piece together
4852 * reply 16 bits at a time.
4853 */
4854 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4855 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4856 failcnt++;
4857 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4858 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004859 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860 hs_reply[u16cnt] = hword;
4861 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4862 }
4863
4864 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4865 failcnt++;
4866 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4867
4868 if (failcnt) {
4869 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4870 ioc->name);
4871 return -failcnt;
4872 }
4873#if 0
4874 else if (u16cnt != (2 * mptReply->MsgLength)) {
4875 return -101;
4876 }
4877 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4878 return -102;
4879 }
4880#endif
4881
Prakash, Sathya436ace72007-07-24 15:42:08 +05304882 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004883 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884
Prakash, Sathya436ace72007-07-24 15:42:08 +05304885 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886 ioc->name, t, u16cnt/2));
4887 return u16cnt/2;
4888}
4889
4890/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004891/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892 * GetLanConfigPages - Fetch LANConfig pages.
4893 * @ioc: Pointer to MPT_ADAPTER structure
4894 *
4895 * Return: 0 for success
4896 * -ENOMEM if no memory available
4897 * -EPERM if not allowed due to ISR context
4898 * -EAGAIN if no msg frames currently available
4899 * -EFAULT for non-successful reply or no reply (timeout)
4900 */
4901static int
4902GetLanConfigPages(MPT_ADAPTER *ioc)
4903{
4904 ConfigPageHeader_t hdr;
4905 CONFIGPARMS cfg;
4906 LANPage0_t *ppage0_alloc;
4907 dma_addr_t page0_dma;
4908 LANPage1_t *ppage1_alloc;
4909 dma_addr_t page1_dma;
4910 int rc = 0;
4911 int data_sz;
4912 int copy_sz;
4913
4914 /* Get LAN Page 0 header */
4915 hdr.PageVersion = 0;
4916 hdr.PageLength = 0;
4917 hdr.PageNumber = 0;
4918 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004919 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920 cfg.physAddr = -1;
4921 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4922 cfg.dir = 0;
4923 cfg.pageAddr = 0;
4924 cfg.timeout = 0;
4925
4926 if ((rc = mpt_config(ioc, &cfg)) != 0)
4927 return rc;
4928
4929 if (hdr.PageLength > 0) {
4930 data_sz = hdr.PageLength * 4;
4931 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4932 rc = -ENOMEM;
4933 if (ppage0_alloc) {
4934 memset((u8 *)ppage0_alloc, 0, data_sz);
4935 cfg.physAddr = page0_dma;
4936 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4937
4938 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4939 /* save the data */
4940 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4941 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4942
4943 }
4944
4945 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4946
4947 /* FIXME!
4948 * Normalize endianness of structure data,
4949 * by byte-swapping all > 1 byte fields!
4950 */
4951
4952 }
4953
4954 if (rc)
4955 return rc;
4956 }
4957
4958 /* Get LAN Page 1 header */
4959 hdr.PageVersion = 0;
4960 hdr.PageLength = 0;
4961 hdr.PageNumber = 1;
4962 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004963 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964 cfg.physAddr = -1;
4965 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4966 cfg.dir = 0;
4967 cfg.pageAddr = 0;
4968
4969 if ((rc = mpt_config(ioc, &cfg)) != 0)
4970 return rc;
4971
4972 if (hdr.PageLength == 0)
4973 return 0;
4974
4975 data_sz = hdr.PageLength * 4;
4976 rc = -ENOMEM;
4977 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4978 if (ppage1_alloc) {
4979 memset((u8 *)ppage1_alloc, 0, data_sz);
4980 cfg.physAddr = page1_dma;
4981 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4982
4983 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4984 /* save the data */
4985 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4986 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4987 }
4988
4989 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4990
4991 /* FIXME!
4992 * Normalize endianness of structure data,
4993 * by byte-swapping all > 1 byte fields!
4994 */
4995
4996 }
4997
4998 return rc;
4999}
5000
5001/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005002/**
5003 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005004 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005005 * @persist_opcode: see below
5006 *
5007 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
5008 * devices not currently present.
5009 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
5010 *
5011 * NOTE: Don't use not this function during interrupt time.
5012 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005013 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005014 */
5015
5016/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
5017int
5018mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
5019{
5020 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
5021 SasIoUnitControlReply_t *sasIoUnitCntrReply;
5022 MPT_FRAME_HDR *mf = NULL;
5023 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305024 int ret = 0;
5025 unsigned long timeleft;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005026
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305027 mutex_lock(&ioc->mptbase_cmds.mutex);
5028
5029 /* init the internal cmd struct */
5030 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
5031 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005032
5033 /* insure garbage is not sent to fw */
5034 switch(persist_opcode) {
5035
5036 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
5037 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
5038 break;
5039
5040 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305041 ret = -1;
5042 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005043 }
5044
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305045 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
5046 __func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005047
5048 /* Get a MF for this command.
5049 */
5050 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305051 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
5052 ret = -1;
5053 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005054 }
5055
5056 mpi_hdr = (MPIHeader_t *) mf;
5057 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
5058 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
5059 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
5060 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
5061 sasIoUnitCntrReq->Operation = persist_opcode;
5062
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005063 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305064 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
5065 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
5066 ret = -ETIME;
5067 printk(KERN_DEBUG "%s: failed\n", __func__);
5068 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
5069 goto out;
5070 if (!timeleft) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09005071 printk(MYIOC_s_WARN_FMT
5072 "Issuing Reset from %s!!, doorbell=0x%08x\n",
5073 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05305074 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305075 mpt_free_msg_frame(ioc, mf);
5076 }
5077 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005078 }
5079
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05305080 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
5081 ret = -1;
5082 goto out;
5083 }
5084
5085 sasIoUnitCntrReply =
5086 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5087 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5088 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5089 __func__, sasIoUnitCntrReply->IOCStatus,
5090 sasIoUnitCntrReply->IOCLogInfo);
5091 printk(KERN_DEBUG "%s: failed\n", __func__);
5092 ret = -1;
5093 } else
5094 printk(KERN_DEBUG "%s: success\n", __func__);
5095 out:
5096
5097 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5098 mutex_unlock(&ioc->mptbase_cmds.mutex);
5099 return ret;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005100}
5101
5102/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005103
5104static void
5105mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5106 MpiEventDataRaid_t * pRaidEventData)
5107{
5108 int volume;
5109 int reason;
5110 int disk;
5111 int status;
5112 int flags;
5113 int state;
5114
5115 volume = pRaidEventData->VolumeID;
5116 reason = pRaidEventData->ReasonCode;
5117 disk = pRaidEventData->PhysDiskNum;
5118 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5119 flags = (status >> 0) & 0xff;
5120 state = (status >> 8) & 0xff;
5121
5122 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5123 return;
5124 }
5125
5126 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5127 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5128 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005129 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5130 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005131 } else {
5132 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5133 ioc->name, volume);
5134 }
5135
5136 switch(reason) {
5137 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5138 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5139 ioc->name);
5140 break;
5141
5142 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5143
5144 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5145 ioc->name);
5146 break;
5147
5148 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5149 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5150 ioc->name);
5151 break;
5152
5153 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5154 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5155 ioc->name,
5156 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5157 ? "optimal"
5158 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5159 ? "degraded"
5160 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5161 ? "failed"
5162 : "state unknown",
5163 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5164 ? ", enabled" : "",
5165 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5166 ? ", quiesced" : "",
5167 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5168 ? ", resync in progress" : "" );
5169 break;
5170
5171 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5172 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5173 ioc->name, disk);
5174 break;
5175
5176 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5177 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5178 ioc->name);
5179 break;
5180
5181 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5182 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5183 ioc->name);
5184 break;
5185
5186 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5187 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5188 ioc->name);
5189 break;
5190
5191 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5192 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5193 ioc->name,
5194 state == MPI_PHYSDISK0_STATUS_ONLINE
5195 ? "online"
5196 : state == MPI_PHYSDISK0_STATUS_MISSING
5197 ? "missing"
5198 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5199 ? "not compatible"
5200 : state == MPI_PHYSDISK0_STATUS_FAILED
5201 ? "failed"
5202 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5203 ? "initializing"
5204 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5205 ? "offline requested"
5206 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5207 ? "failed requested"
5208 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5209 ? "offline"
5210 : "state unknown",
5211 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5212 ? ", out of sync" : "",
5213 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5214 ? ", quiesced" : "" );
5215 break;
5216
5217 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5218 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5219 ioc->name, disk);
5220 break;
5221
5222 case MPI_EVENT_RAID_RC_SMART_DATA:
5223 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5224 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5225 break;
5226
5227 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5228 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5229 ioc->name, disk);
5230 break;
5231 }
5232}
5233
5234/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005235/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5237 * @ioc: Pointer to MPT_ADAPTER structure
5238 *
5239 * Returns: 0 for success
5240 * -ENOMEM if no memory available
5241 * -EPERM if not allowed due to ISR context
5242 * -EAGAIN if no msg frames currently available
5243 * -EFAULT for non-successful reply or no reply (timeout)
5244 */
5245static int
5246GetIoUnitPage2(MPT_ADAPTER *ioc)
5247{
5248 ConfigPageHeader_t hdr;
5249 CONFIGPARMS cfg;
5250 IOUnitPage2_t *ppage_alloc;
5251 dma_addr_t page_dma;
5252 int data_sz;
5253 int rc;
5254
5255 /* Get the page header */
5256 hdr.PageVersion = 0;
5257 hdr.PageLength = 0;
5258 hdr.PageNumber = 2;
5259 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005260 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261 cfg.physAddr = -1;
5262 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5263 cfg.dir = 0;
5264 cfg.pageAddr = 0;
5265 cfg.timeout = 0;
5266
5267 if ((rc = mpt_config(ioc, &cfg)) != 0)
5268 return rc;
5269
5270 if (hdr.PageLength == 0)
5271 return 0;
5272
5273 /* Read the config page */
5274 data_sz = hdr.PageLength * 4;
5275 rc = -ENOMEM;
5276 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5277 if (ppage_alloc) {
5278 memset((u8 *)ppage_alloc, 0, data_sz);
5279 cfg.physAddr = page_dma;
5280 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5281
5282 /* If Good, save data */
5283 if ((rc = mpt_config(ioc, &cfg)) == 0)
5284 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5285
5286 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5287 }
5288
5289 return rc;
5290}
5291
5292/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005293/**
5294 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005295 * @ioc: Pointer to a Adapter Strucutre
5296 * @portnum: IOC port number
5297 *
5298 * Return: -EFAULT if read of config page header fails
5299 * or if no nvram
5300 * If read of SCSI Port Page 0 fails,
5301 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5302 * Adapter settings: async, narrow
5303 * Return 1
5304 * If read of SCSI Port Page 2 fails,
5305 * Adapter settings valid
5306 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5307 * Return 1
5308 * Else
5309 * Both valid
5310 * Return 0
5311 * CHECK - what type of locking mechanisms should be used????
5312 */
5313static int
5314mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5315{
5316 u8 *pbuf;
5317 dma_addr_t buf_dma;
5318 CONFIGPARMS cfg;
5319 ConfigPageHeader_t header;
5320 int ii;
5321 int data, rc = 0;
5322
5323 /* Allocate memory
5324 */
5325 if (!ioc->spi_data.nvram) {
5326 int sz;
5327 u8 *mem;
5328 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5329 mem = kmalloc(sz, GFP_ATOMIC);
5330 if (mem == NULL)
5331 return -EFAULT;
5332
5333 ioc->spi_data.nvram = (int *) mem;
5334
Prakash, Sathya436ace72007-07-24 15:42:08 +05305335 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005336 ioc->name, ioc->spi_data.nvram, sz));
5337 }
5338
5339 /* Invalidate NVRAM information
5340 */
5341 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5342 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5343 }
5344
5345 /* Read SPP0 header, allocate memory, then read page.
5346 */
5347 header.PageVersion = 0;
5348 header.PageLength = 0;
5349 header.PageNumber = 0;
5350 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005351 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352 cfg.physAddr = -1;
5353 cfg.pageAddr = portnum;
5354 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5355 cfg.dir = 0;
5356 cfg.timeout = 0; /* use default */
5357 if (mpt_config(ioc, &cfg) != 0)
5358 return -EFAULT;
5359
5360 if (header.PageLength > 0) {
5361 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5362 if (pbuf) {
5363 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5364 cfg.physAddr = buf_dma;
5365 if (mpt_config(ioc, &cfg) != 0) {
5366 ioc->spi_data.maxBusWidth = MPT_NARROW;
5367 ioc->spi_data.maxSyncOffset = 0;
5368 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5369 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5370 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305371 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5372 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005373 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005374 } else {
5375 /* Save the Port Page 0 data
5376 */
5377 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5378 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5379 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5380
5381 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5382 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005383 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5384 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385 ioc->name, pPP0->Capabilities));
5386 }
5387 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5388 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5389 if (data) {
5390 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5391 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5392 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305393 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5394 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005395 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396 } else {
5397 ioc->spi_data.maxSyncOffset = 0;
5398 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5399 }
5400
5401 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5402
5403 /* Update the minSyncFactor based on bus type.
5404 */
5405 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5406 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5407
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005408 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305410 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5411 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005412 ioc->name, ioc->spi_data.minSyncFactor));
5413 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005414 }
5415 }
5416 if (pbuf) {
5417 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5418 }
5419 }
5420 }
5421
5422 /* SCSI Port Page 2 - Read the header then the page.
5423 */
5424 header.PageVersion = 0;
5425 header.PageLength = 0;
5426 header.PageNumber = 2;
5427 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005428 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429 cfg.physAddr = -1;
5430 cfg.pageAddr = portnum;
5431 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5432 cfg.dir = 0;
5433 if (mpt_config(ioc, &cfg) != 0)
5434 return -EFAULT;
5435
5436 if (header.PageLength > 0) {
5437 /* Allocate memory and read SCSI Port Page 2
5438 */
5439 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5440 if (pbuf) {
5441 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5442 cfg.physAddr = buf_dma;
5443 if (mpt_config(ioc, &cfg) != 0) {
5444 /* Nvram data is left with INVALID mark
5445 */
5446 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005447 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5448
5449 /* This is an ATTO adapter, read Page2 accordingly
5450 */
5451 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5452 ATTODeviceInfo_t *pdevice = NULL;
5453 u16 ATTOFlags;
5454
5455 /* Save the Port Page 2 data
5456 * (reformat into a 32bit quantity)
5457 */
5458 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5459 pdevice = &pPP2->DeviceSettings[ii];
5460 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5461 data = 0;
5462
5463 /* Translate ATTO device flags to LSI format
5464 */
5465 if (ATTOFlags & ATTOFLAG_DISC)
5466 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5467 if (ATTOFlags & ATTOFLAG_ID_ENB)
5468 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5469 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5470 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5471 if (ATTOFlags & ATTOFLAG_TAGGED)
5472 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5473 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5474 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5475
5476 data = (data << 16) | (pdevice->Period << 8) | 10;
5477 ioc->spi_data.nvram[ii] = data;
5478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 } else {
5480 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5481 MpiDeviceInfo_t *pdevice = NULL;
5482
Moore, Ericd8e925d2006-01-16 18:53:06 -07005483 /*
5484 * Save "Set to Avoid SCSI Bus Resets" flag
5485 */
5486 ioc->spi_data.bus_reset =
5487 (le32_to_cpu(pPP2->PortFlags) &
5488 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5489 0 : 1 ;
5490
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 /* Save the Port Page 2 data
5492 * (reformat into a 32bit quantity)
5493 */
5494 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5495 ioc->spi_data.PortFlags = data;
5496 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5497 pdevice = &pPP2->DeviceSettings[ii];
5498 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5499 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5500 ioc->spi_data.nvram[ii] = data;
5501 }
5502 }
5503
5504 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5505 }
5506 }
5507
5508 /* Update Adapter limits with those from NVRAM
5509 * Comment: Don't need to do this. Target performance
5510 * parameters will never exceed the adapters limits.
5511 */
5512
5513 return rc;
5514}
5515
5516/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005517/**
5518 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005519 * @ioc: Pointer to a Adapter Strucutre
5520 * @portnum: IOC port number
5521 *
5522 * Return: -EFAULT if read of config page header fails
5523 * or 0 if success.
5524 */
5525static int
5526mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5527{
5528 CONFIGPARMS cfg;
5529 ConfigPageHeader_t header;
5530
5531 /* Read the SCSI Device Page 1 header
5532 */
5533 header.PageVersion = 0;
5534 header.PageLength = 0;
5535 header.PageNumber = 1;
5536 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005537 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538 cfg.physAddr = -1;
5539 cfg.pageAddr = portnum;
5540 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5541 cfg.dir = 0;
5542 cfg.timeout = 0;
5543 if (mpt_config(ioc, &cfg) != 0)
5544 return -EFAULT;
5545
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005546 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5547 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005548
5549 header.PageVersion = 0;
5550 header.PageLength = 0;
5551 header.PageNumber = 0;
5552 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5553 if (mpt_config(ioc, &cfg) != 0)
5554 return -EFAULT;
5555
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005556 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5557 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558
Prakash, Sathya436ace72007-07-24 15:42:08 +05305559 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005560 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5561
Prakash, Sathya436ace72007-07-24 15:42:08 +05305562 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005563 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5564 return 0;
5565}
5566
Eric Mooreb506ade2007-01-29 09:45:37 -07005567/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005568 * mpt_inactive_raid_list_free - This clears this link list.
5569 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005570 **/
5571static void
5572mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5573{
5574 struct inactive_raid_component_info *component_info, *pNext;
5575
5576 if (list_empty(&ioc->raid_data.inactive_list))
5577 return;
5578
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005579 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005580 list_for_each_entry_safe(component_info, pNext,
5581 &ioc->raid_data.inactive_list, list) {
5582 list_del(&component_info->list);
5583 kfree(component_info);
5584 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005585 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005586}
5587
5588/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005589 * 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 -07005590 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005591 * @ioc : pointer to per adapter structure
5592 * @channel : volume channel
5593 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005594 **/
5595static void
5596mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5597{
5598 CONFIGPARMS cfg;
5599 ConfigPageHeader_t hdr;
5600 dma_addr_t dma_handle;
5601 pRaidVolumePage0_t buffer = NULL;
5602 int i;
5603 RaidPhysDiskPage0_t phys_disk;
5604 struct inactive_raid_component_info *component_info;
5605 int handle_inactive_volumes;
5606
5607 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5608 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5609 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5610 cfg.pageAddr = (channel << 8) + id;
5611 cfg.cfghdr.hdr = &hdr;
5612 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5613
5614 if (mpt_config(ioc, &cfg) != 0)
5615 goto out;
5616
5617 if (!hdr.PageLength)
5618 goto out;
5619
5620 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5621 &dma_handle);
5622
5623 if (!buffer)
5624 goto out;
5625
5626 cfg.physAddr = dma_handle;
5627 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5628
5629 if (mpt_config(ioc, &cfg) != 0)
5630 goto out;
5631
5632 if (!buffer->NumPhysDisks)
5633 goto out;
5634
5635 handle_inactive_volumes =
5636 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5637 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5638 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5639 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5640
5641 if (!handle_inactive_volumes)
5642 goto out;
5643
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005644 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005645 for (i = 0; i < buffer->NumPhysDisks; i++) {
5646 if(mpt_raid_phys_disk_pg0(ioc,
5647 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5648 continue;
5649
5650 if ((component_info = kmalloc(sizeof (*component_info),
5651 GFP_KERNEL)) == NULL)
5652 continue;
5653
5654 component_info->volumeID = id;
5655 component_info->volumeBus = channel;
5656 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5657 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5658 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5659 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5660
5661 list_add_tail(&component_info->list,
5662 &ioc->raid_data.inactive_list);
5663 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005664 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005665
5666 out:
5667 if (buffer)
5668 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5669 dma_handle);
5670}
5671
5672/**
5673 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5674 * @ioc: Pointer to a Adapter Structure
5675 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5676 * @phys_disk: requested payload data returned
5677 *
5678 * Return:
5679 * 0 on success
5680 * -EFAULT if read of config page header fails or data pointer not NULL
5681 * -ENOMEM if pci_alloc failed
5682 **/
5683int
Kashyap, Desai2f187862009-05-29 16:52:37 +05305684mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
5685 RaidPhysDiskPage0_t *phys_disk)
Eric Mooreb506ade2007-01-29 09:45:37 -07005686{
Kashyap, Desai2f187862009-05-29 16:52:37 +05305687 CONFIGPARMS cfg;
5688 ConfigPageHeader_t hdr;
Eric Mooreb506ade2007-01-29 09:45:37 -07005689 dma_addr_t dma_handle;
5690 pRaidPhysDiskPage0_t buffer = NULL;
5691 int rc;
5692
5693 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5694 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
Kashyap, Desai2f187862009-05-29 16:52:37 +05305695 memset(phys_disk, 0, sizeof(RaidPhysDiskPage0_t));
Eric Mooreb506ade2007-01-29 09:45:37 -07005696
Kashyap, Desai2f187862009-05-29 16:52:37 +05305697 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE0_PAGEVERSION;
Eric Mooreb506ade2007-01-29 09:45:37 -07005698 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5699 cfg.cfghdr.hdr = &hdr;
5700 cfg.physAddr = -1;
5701 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5702
5703 if (mpt_config(ioc, &cfg) != 0) {
5704 rc = -EFAULT;
5705 goto out;
5706 }
5707
5708 if (!hdr.PageLength) {
5709 rc = -EFAULT;
5710 goto out;
5711 }
5712
5713 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5714 &dma_handle);
5715
5716 if (!buffer) {
5717 rc = -ENOMEM;
5718 goto out;
5719 }
5720
5721 cfg.physAddr = dma_handle;
5722 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5723 cfg.pageAddr = phys_disk_num;
5724
5725 if (mpt_config(ioc, &cfg) != 0) {
5726 rc = -EFAULT;
5727 goto out;
5728 }
5729
5730 rc = 0;
5731 memcpy(phys_disk, buffer, sizeof(*buffer));
5732 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5733
5734 out:
5735
5736 if (buffer)
5737 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5738 dma_handle);
5739
5740 return rc;
5741}
5742
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743/**
Kashyap, Desaia7938b02009-05-29 16:53:56 +05305744 * mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
5745 * @ioc: Pointer to a Adapter Structure
5746 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5747 *
5748 * Return:
5749 * returns number paths
5750 **/
5751int
5752mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
5753{
5754 CONFIGPARMS cfg;
5755 ConfigPageHeader_t hdr;
5756 dma_addr_t dma_handle;
5757 pRaidPhysDiskPage1_t buffer = NULL;
5758 int rc;
5759
5760 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5761 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5762
5763 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5764 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5765 hdr.PageNumber = 1;
5766 cfg.cfghdr.hdr = &hdr;
5767 cfg.physAddr = -1;
5768 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5769
5770 if (mpt_config(ioc, &cfg) != 0) {
5771 rc = 0;
5772 goto out;
5773 }
5774
5775 if (!hdr.PageLength) {
5776 rc = 0;
5777 goto out;
5778 }
5779
5780 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5781 &dma_handle);
5782
5783 if (!buffer) {
5784 rc = 0;
5785 goto out;
5786 }
5787
5788 cfg.physAddr = dma_handle;
5789 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5790 cfg.pageAddr = phys_disk_num;
5791
5792 if (mpt_config(ioc, &cfg) != 0) {
5793 rc = 0;
5794 goto out;
5795 }
5796
5797 rc = buffer->NumPhysDiskPaths;
5798 out:
5799
5800 if (buffer)
5801 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5802 dma_handle);
5803
5804 return rc;
5805}
5806EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
5807
5808/**
5809 * mpt_raid_phys_disk_pg1 - returns phys disk page 1
5810 * @ioc: Pointer to a Adapter Structure
5811 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5812 * @phys_disk: requested payload data returned
5813 *
5814 * Return:
5815 * 0 on success
5816 * -EFAULT if read of config page header fails or data pointer not NULL
5817 * -ENOMEM if pci_alloc failed
5818 **/
5819int
5820mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
5821 RaidPhysDiskPage1_t *phys_disk)
5822{
5823 CONFIGPARMS cfg;
5824 ConfigPageHeader_t hdr;
5825 dma_addr_t dma_handle;
5826 pRaidPhysDiskPage1_t buffer = NULL;
5827 int rc;
5828 int i;
5829 __le64 sas_address;
5830
5831 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5832 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5833 rc = 0;
5834
5835 hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
5836 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5837 hdr.PageNumber = 1;
5838 cfg.cfghdr.hdr = &hdr;
5839 cfg.physAddr = -1;
5840 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5841
5842 if (mpt_config(ioc, &cfg) != 0) {
5843 rc = -EFAULT;
5844 goto out;
5845 }
5846
5847 if (!hdr.PageLength) {
5848 rc = -EFAULT;
5849 goto out;
5850 }
5851
5852 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5853 &dma_handle);
5854
5855 if (!buffer) {
5856 rc = -ENOMEM;
5857 goto out;
5858 }
5859
5860 cfg.physAddr = dma_handle;
5861 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5862 cfg.pageAddr = phys_disk_num;
5863
5864 if (mpt_config(ioc, &cfg) != 0) {
5865 rc = -EFAULT;
5866 goto out;
5867 }
5868
5869 phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
5870 phys_disk->PhysDiskNum = phys_disk_num;
5871 for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
5872 phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
5873 phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
5874 phys_disk->Path[i].OwnerIdentifier =
5875 buffer->Path[i].OwnerIdentifier;
5876 phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
5877 memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
5878 sas_address = le64_to_cpu(sas_address);
5879 memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
5880 memcpy(&sas_address,
5881 &buffer->Path[i].OwnerWWID, sizeof(__le64));
5882 sas_address = le64_to_cpu(sas_address);
5883 memcpy(&phys_disk->Path[i].OwnerWWID,
5884 &sas_address, sizeof(__le64));
5885 }
5886
5887 out:
5888
5889 if (buffer)
5890 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5891 dma_handle);
5892
5893 return rc;
5894}
5895EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
5896
5897
5898/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005899 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5900 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005901 *
5902 * Return:
5903 * 0 on success
5904 * -EFAULT if read of config page header fails or data pointer not NULL
5905 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005906 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005907int
5908mpt_findImVolumes(MPT_ADAPTER *ioc)
5909{
5910 IOCPage2_t *pIoc2;
5911 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005912 dma_addr_t ioc2_dma;
5913 CONFIGPARMS cfg;
5914 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915 int rc = 0;
5916 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005917 int i;
5918
5919 if (!ioc->ir_firmware)
5920 return 0;
5921
5922 /* Free the old page
5923 */
5924 kfree(ioc->raid_data.pIocPg2);
5925 ioc->raid_data.pIocPg2 = NULL;
5926 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005927
5928 /* Read IOCP2 header then the page.
5929 */
5930 header.PageVersion = 0;
5931 header.PageLength = 0;
5932 header.PageNumber = 2;
5933 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005934 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005935 cfg.physAddr = -1;
5936 cfg.pageAddr = 0;
5937 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5938 cfg.dir = 0;
5939 cfg.timeout = 0;
5940 if (mpt_config(ioc, &cfg) != 0)
5941 return -EFAULT;
5942
5943 if (header.PageLength == 0)
5944 return -EFAULT;
5945
5946 iocpage2sz = header.PageLength * 4;
5947 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5948 if (!pIoc2)
5949 return -ENOMEM;
5950
5951 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5952 cfg.physAddr = ioc2_dma;
5953 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005954 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955
Eric Mooreb506ade2007-01-29 09:45:37 -07005956 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5957 if (!mem)
5958 goto out;
5959
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005961 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005962
Eric Mooreb506ade2007-01-29 09:45:37 -07005963 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005964
Eric Mooreb506ade2007-01-29 09:45:37 -07005965 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5966 mpt_inactive_raid_volumes(ioc,
5967 pIoc2->RaidVolume[i].VolumeBus,
5968 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005969
Eric Mooreb506ade2007-01-29 09:45:37 -07005970 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005971 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5972
5973 return rc;
5974}
5975
Moore, Ericc972c702006-03-14 09:14:06 -07005976static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5978{
5979 IOCPage3_t *pIoc3;
5980 u8 *mem;
5981 CONFIGPARMS cfg;
5982 ConfigPageHeader_t header;
5983 dma_addr_t ioc3_dma;
5984 int iocpage3sz = 0;
5985
5986 /* Free the old page
5987 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005988 kfree(ioc->raid_data.pIocPg3);
5989 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990
5991 /* There is at least one physical disk.
5992 * Read and save IOC Page 3
5993 */
5994 header.PageVersion = 0;
5995 header.PageLength = 0;
5996 header.PageNumber = 3;
5997 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005998 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005999 cfg.physAddr = -1;
6000 cfg.pageAddr = 0;
6001 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6002 cfg.dir = 0;
6003 cfg.timeout = 0;
6004 if (mpt_config(ioc, &cfg) != 0)
6005 return 0;
6006
6007 if (header.PageLength == 0)
6008 return 0;
6009
6010 /* Read Header good, alloc memory
6011 */
6012 iocpage3sz = header.PageLength * 4;
6013 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
6014 if (!pIoc3)
6015 return 0;
6016
6017 /* Read the Page and save the data
6018 * into malloc'd memory.
6019 */
6020 cfg.physAddr = ioc3_dma;
6021 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6022 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07006023 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006024 if (mem) {
6025 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06006026 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006027 }
6028 }
6029
6030 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
6031
6032 return 0;
6033}
6034
6035static void
6036mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
6037{
6038 IOCPage4_t *pIoc4;
6039 CONFIGPARMS cfg;
6040 ConfigPageHeader_t header;
6041 dma_addr_t ioc4_dma;
6042 int iocpage4sz;
6043
6044 /* Read and save IOC Page 4
6045 */
6046 header.PageVersion = 0;
6047 header.PageLength = 0;
6048 header.PageNumber = 4;
6049 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006050 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006051 cfg.physAddr = -1;
6052 cfg.pageAddr = 0;
6053 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6054 cfg.dir = 0;
6055 cfg.timeout = 0;
6056 if (mpt_config(ioc, &cfg) != 0)
6057 return;
6058
6059 if (header.PageLength == 0)
6060 return;
6061
6062 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
6063 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
6064 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
6065 if (!pIoc4)
6066 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06006067 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006068 } else {
6069 ioc4_dma = ioc->spi_data.IocPg4_dma;
6070 iocpage4sz = ioc->spi_data.IocPg4Sz;
6071 }
6072
6073 /* Read the Page into dma memory.
6074 */
6075 cfg.physAddr = ioc4_dma;
6076 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6077 if (mpt_config(ioc, &cfg) == 0) {
6078 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
6079 ioc->spi_data.IocPg4_dma = ioc4_dma;
6080 ioc->spi_data.IocPg4Sz = iocpage4sz;
6081 } else {
6082 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
6083 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06006084 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085 }
6086}
6087
6088static void
6089mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
6090{
6091 IOCPage1_t *pIoc1;
6092 CONFIGPARMS cfg;
6093 ConfigPageHeader_t header;
6094 dma_addr_t ioc1_dma;
6095 int iocpage1sz = 0;
6096 u32 tmp;
6097
6098 /* Check the Coalescing Timeout in IOC Page 1
6099 */
6100 header.PageVersion = 0;
6101 header.PageLength = 0;
6102 header.PageNumber = 1;
6103 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006104 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006105 cfg.physAddr = -1;
6106 cfg.pageAddr = 0;
6107 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6108 cfg.dir = 0;
6109 cfg.timeout = 0;
6110 if (mpt_config(ioc, &cfg) != 0)
6111 return;
6112
6113 if (header.PageLength == 0)
6114 return;
6115
6116 /* Read Header good, alloc memory
6117 */
6118 iocpage1sz = header.PageLength * 4;
6119 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
6120 if (!pIoc1)
6121 return;
6122
6123 /* Read the Page and check coalescing timeout
6124 */
6125 cfg.physAddr = ioc1_dma;
6126 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6127 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306128
Linus Torvalds1da177e2005-04-16 15:20:36 -07006129 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
6130 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
6131 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
6132
Prakash, Sathya436ace72007-07-24 15:42:08 +05306133 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006134 ioc->name, tmp));
6135
6136 if (tmp > MPT_COALESCING_TIMEOUT) {
6137 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
6138
6139 /* Write NVRAM and current
6140 */
6141 cfg.dir = 1;
6142 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
6143 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306144 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006145 ioc->name, MPT_COALESCING_TIMEOUT));
6146
6147 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
6148 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306149 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6150 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006151 ioc->name, MPT_COALESCING_TIMEOUT));
6152 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306153 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6154 "Reset NVRAM Coalescing Timeout Failed\n",
6155 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006156 }
6157
6158 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306159 dprintk(ioc, printk(MYIOC_s_WARN_FMT
6160 "Reset of Current Coalescing Timeout Failed!\n",
6161 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006162 }
6163 }
6164
6165 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306166 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006167 }
6168 }
6169
6170 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
6171
6172 return;
6173}
6174
Prakash, Sathyaedb90682007-07-17 14:39:14 +05306175static void
6176mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
6177{
6178 CONFIGPARMS cfg;
6179 ConfigPageHeader_t hdr;
6180 dma_addr_t buf_dma;
6181 ManufacturingPage0_t *pbuf = NULL;
6182
6183 memset(&cfg, 0 , sizeof(CONFIGPARMS));
6184 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
6185
6186 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
6187 cfg.cfghdr.hdr = &hdr;
6188 cfg.physAddr = -1;
6189 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6190 cfg.timeout = 10;
6191
6192 if (mpt_config(ioc, &cfg) != 0)
6193 goto out;
6194
6195 if (!cfg.cfghdr.hdr->PageLength)
6196 goto out;
6197
6198 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
6199 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
6200 if (!pbuf)
6201 goto out;
6202
6203 cfg.physAddr = buf_dma;
6204
6205 if (mpt_config(ioc, &cfg) != 0)
6206 goto out;
6207
6208 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
6209 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
6210 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
6211
6212 out:
6213
6214 if (pbuf)
6215 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
6216}
6217
Linus Torvalds1da177e2005-04-16 15:20:36 -07006218/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006219/**
6220 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07006221 * @ioc: Pointer to MPT_ADAPTER structure
6222 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05306223 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07006224 */
6225static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05306226SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006227{
Kashyap, Desaifd761752009-05-29 16:39:06 +05306228 EventNotification_t evn;
6229 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006230
Kashyap, Desaifd761752009-05-29 16:39:06 +05306231 memset(&evn, 0, sizeof(EventNotification_t));
6232 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006233
Kashyap, Desaifd761752009-05-29 16:39:06 +05306234 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
6235 evn.Switch = EvSwitch;
6236 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006237
Kashyap, Desaifd761752009-05-29 16:39:06 +05306238 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6239 "Sending EventNotification (%d) request %p\n",
6240 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241
Kashyap, Desaifd761752009-05-29 16:39:06 +05306242 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6243 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6244 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006245}
6246
6247/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6248/**
6249 * SendEventAck - Send EventAck request to MPT adapter.
6250 * @ioc: Pointer to MPT_ADAPTER structure
6251 * @evnp: Pointer to original EventNotification request
6252 */
6253static int
6254SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6255{
6256 EventAck_t *pAck;
6257
6258 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306259 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306260 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006261 return -1;
6262 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006263
Prakash, Sathya436ace72007-07-24 15:42:08 +05306264 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006265
6266 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6267 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006268 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006269 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006270 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006271 pAck->Event = evnp->Event;
6272 pAck->EventContext = evnp->EventContext;
6273
6274 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6275
6276 return 0;
6277}
6278
6279/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6280/**
6281 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006282 * @ioc: Pointer to an adapter structure
6283 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006284 * action, page address, direction, physical address
6285 * and pointer to a configuration page header
6286 * Page header is updated.
6287 *
6288 * Returns 0 for success
6289 * -EPERM if not allowed due to ISR context
6290 * -EAGAIN if no msg frames currently available
6291 * -EFAULT for non-successful reply or no reply (timeout)
6292 */
6293int
6294mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6295{
6296 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306297 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006298 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006299 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306300 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006301 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306302 long timeout;
6303 int ret;
6304 u8 page_type = 0, extend_page;
6305 unsigned long timeleft;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306306 unsigned long flags;
6307 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306308 u8 issue_hard_reset = 0;
6309 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006310
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006311 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006312 * to be in ISR context, because that is fatal!
6313 */
6314 in_isr = in_interrupt();
6315 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306316 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006317 ioc->name));
6318 return -EPERM;
Kashyap, Desai2f187862009-05-29 16:52:37 +05306319 }
6320
6321 /* don't send a config page during diag reset */
6322 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6323 if (ioc->ioc_reset_in_progress) {
6324 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6325 "%s: busy with host reset\n", ioc->name, __func__));
6326 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6327 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006328 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306329 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006330
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306331 /* don't send if no chance of success */
6332 if (!ioc->active ||
6333 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6334 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6335 "%s: ioc not operational, %d, %xh\n",
6336 ioc->name, __func__, ioc->active,
6337 mpt_GetIocState(ioc, 0)));
6338 return -EFAULT;
6339 }
6340
6341 retry_config:
6342 mutex_lock(&ioc->mptbase_cmds.mutex);
6343 /* init the internal cmd struct */
6344 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6345 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6346
Linus Torvalds1da177e2005-04-16 15:20:36 -07006347 /* Get and Populate a free Frame
6348 */
6349 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306350 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6351 "mpt_config: no msg frames!\n", ioc->name));
6352 ret = -EAGAIN;
6353 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006354 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306355
Linus Torvalds1da177e2005-04-16 15:20:36 -07006356 pReq = (Config_t *)mf;
6357 pReq->Action = pCfg->action;
6358 pReq->Reserved = 0;
6359 pReq->ChainOffset = 0;
6360 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006361
6362 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006363 pReq->ExtPageLength = 0;
6364 pReq->ExtPageType = 0;
6365 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006366
Linus Torvalds1da177e2005-04-16 15:20:36 -07006367 for (ii=0; ii < 8; ii++)
6368 pReq->Reserved2[ii] = 0;
6369
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006370 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6371 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6372 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6373 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6374
6375 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6376 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6377 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6378 pReq->ExtPageType = pExtHdr->ExtPageType;
6379 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6380
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306381 /* Page Length must be treated as a reserved field for the
6382 * extended header.
6383 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006384 pReq->Header.PageLength = 0;
6385 }
6386
Linus Torvalds1da177e2005-04-16 15:20:36 -07006387 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6388
6389 /* Add a SGE to the config request.
6390 */
6391 if (pCfg->dir)
6392 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6393 else
6394 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6395
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306396 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6397 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006398 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306399 page_type = pReq->ExtPageType;
6400 extend_page = 1;
6401 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006402 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306403 page_type = pReq->Header.PageType;
6404 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006406
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306407 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6408 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6409 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6410
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306411 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306412 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006413 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306414 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6415 timeout);
6416 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6417 ret = -ETIME;
6418 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6419 "Failed Sending Config request type 0x%x, page 0x%x,"
6420 " action %d, status %xh, time left %ld\n\n",
6421 ioc->name, page_type, pReq->Header.PageNumber,
6422 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6423 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6424 goto out;
6425 if (!timeleft)
6426 issue_hard_reset = 1;
6427 goto out;
6428 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006429
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306430 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6431 ret = -1;
6432 goto out;
6433 }
6434 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6435 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6436 if (ret == MPI_IOCSTATUS_SUCCESS) {
6437 if (extend_page) {
6438 pCfg->cfghdr.ehdr->ExtPageLength =
6439 le16_to_cpu(pReply->ExtPageLength);
6440 pCfg->cfghdr.ehdr->ExtPageType =
6441 pReply->ExtPageType;
6442 }
6443 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6444 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6445 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6446 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006447
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306448 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006449
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306450 if (retry_count)
6451 printk(MYIOC_s_INFO_FMT "Retry completed "
6452 "ret=0x%x timeleft=%ld\n",
6453 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006454
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306455 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6456 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006457
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306458out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006459
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306460 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6461 mutex_unlock(&ioc->mptbase_cmds.mutex);
6462 if (issue_hard_reset) {
6463 issue_hard_reset = 0;
Kei Tokunaga97009a22010-06-22 19:01:51 +09006464 printk(MYIOC_s_WARN_FMT
6465 "Issuing Reset from %s!!, doorbell=0x%08x\n",
6466 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaib3b97312010-03-18 19:14:51 +05306467 if (retry_count == 0) {
6468 if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0)
6469 retry_count++;
6470 } else
6471 mpt_HardResetHandler(ioc, CAN_SLEEP);
6472
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306473 mpt_free_msg_frame(ioc, mf);
6474 /* attempt one retry for a timed out command */
Kashyap, Desaib3b97312010-03-18 19:14:51 +05306475 if (retry_count < 2) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306476 printk(MYIOC_s_INFO_FMT
6477 "Attempting Retry Config request"
6478 " type 0x%x, page 0x%x,"
6479 " action %d\n", ioc->name, page_type,
6480 pCfg->cfghdr.hdr->PageNumber, pCfg->action);
6481 retry_count++;
6482 goto retry_config;
6483 }
6484 }
6485 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006486
Linus Torvalds1da177e2005-04-16 15:20:36 -07006487}
6488
6489/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006490/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006491 * mpt_ioc_reset - Base cleanup for hard reset
6492 * @ioc: Pointer to the adapter structure
6493 * @reset_phase: Indicates pre- or post-reset functionality
6494 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006495 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006496 */
6497static int
6498mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6499{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306500 switch (reset_phase) {
6501 case MPT_IOC_SETUP_RESET:
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306502 ioc->taskmgmt_quiesce_io = 1;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306503 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6504 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
6505 break;
6506 case MPT_IOC_PRE_RESET:
6507 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6508 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
6509 break;
6510 case MPT_IOC_POST_RESET:
6511 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6512 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
6513/* wake up mptbase_cmds */
6514 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6515 ioc->mptbase_cmds.status |=
6516 MPT_MGMT_STATUS_DID_IOCRESET;
6517 complete(&ioc->mptbase_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006518 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05306519/* wake up taskmgmt_cmds */
6520 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
6521 ioc->taskmgmt_cmds.status |=
6522 MPT_MGMT_STATUS_DID_IOCRESET;
6523 complete(&ioc->taskmgmt_cmds.done);
6524 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306525 break;
6526 default:
6527 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006528 }
6529
6530 return 1; /* currently means nothing really */
6531}
6532
6533
6534#ifdef CONFIG_PROC_FS /* { */
6535/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6536/*
6537 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6538 */
6539/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006540/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006541 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6542 *
6543 * Returns 0 for success, non-zero for failure.
6544 */
6545static int
6546procmpt_create(void)
6547{
6548 struct proc_dir_entry *ent;
6549
6550 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6551 if (mpt_proc_root_dir == NULL)
6552 return -ENOTDIR;
6553
6554 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6555 if (ent)
6556 ent->read_proc = procmpt_summary_read;
6557
6558 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6559 if (ent)
6560 ent->read_proc = procmpt_version_read;
6561
6562 return 0;
6563}
6564
6565/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006566/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006567 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6568 *
6569 * Returns 0 for success, non-zero for failure.
6570 */
6571static void
6572procmpt_destroy(void)
6573{
6574 remove_proc_entry("version", mpt_proc_root_dir);
6575 remove_proc_entry("summary", mpt_proc_root_dir);
6576 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6577}
6578
6579/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006580/**
6581 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006582 * @buf: Pointer to area to write information
6583 * @start: Pointer to start pointer
6584 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006585 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006586 * @eof: Pointer to EOF integer
6587 * @data: Pointer
6588 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006589 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006590 * Returns number of characters written to process performing the read.
6591 */
6592static int
6593procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6594{
6595 MPT_ADAPTER *ioc;
6596 char *out = buf;
6597 int len;
6598
6599 if (data) {
6600 int more = 0;
6601
6602 ioc = data;
6603 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6604
6605 out += more;
6606 } else {
6607 list_for_each_entry(ioc, &ioc_list, list) {
6608 int more = 0;
6609
6610 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6611
6612 out += more;
6613 if ((out-buf) >= request)
6614 break;
6615 }
6616 }
6617
6618 len = out - buf;
6619
6620 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6621}
6622
6623/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006624/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006625 * procmpt_version_read - Handle read request from /proc/mpt/version.
6626 * @buf: Pointer to area to write information
6627 * @start: Pointer to start pointer
6628 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006629 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006630 * @eof: Pointer to EOF integer
6631 * @data: Pointer
6632 *
6633 * Returns number of characters written to process performing the read.
6634 */
6635static int
6636procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6637{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306638 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006639 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006640 char *drvname;
6641 int len;
6642
6643 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6644 len += sprintf(buf+len, " Fusion MPT base driver\n");
6645
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006646 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006647 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006648 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306649 if (MptCallbacks[cb_idx]) {
6650 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006651 case MPTSPI_DRIVER:
6652 if (!scsi++) drvname = "SPI host";
6653 break;
6654 case MPTFC_DRIVER:
6655 if (!fc++) drvname = "FC host";
6656 break;
6657 case MPTSAS_DRIVER:
6658 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006659 break;
6660 case MPTLAN_DRIVER:
6661 if (!lan++) drvname = "LAN";
6662 break;
6663 case MPTSTM_DRIVER:
6664 if (!targ++) drvname = "SCSI target";
6665 break;
6666 case MPTCTL_DRIVER:
6667 if (!ctl++) drvname = "ioctl";
6668 break;
6669 }
6670
6671 if (drvname)
6672 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6673 }
6674 }
6675
6676 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6677}
6678
6679/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006680/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006681 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6682 * @buf: Pointer to area to write information
6683 * @start: Pointer to start pointer
6684 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006685 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006686 * @eof: Pointer to EOF integer
6687 * @data: Pointer
6688 *
6689 * Returns number of characters written to process performing the read.
6690 */
6691static int
6692procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6693{
6694 MPT_ADAPTER *ioc = data;
6695 int len;
6696 char expVer[32];
6697 int sz;
6698 int p;
6699
6700 mpt_get_fw_exp_ver(expVer, ioc);
6701
6702 len = sprintf(buf, "%s:", ioc->name);
6703 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6704 len += sprintf(buf+len, " (f/w download boot flag set)");
6705// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6706// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6707
6708 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6709 ioc->facts.ProductID,
6710 ioc->prod_name);
6711 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6712 if (ioc->facts.FWImageSize)
6713 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6714 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6715 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6716 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6717
6718 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6719 ioc->facts.CurrentHostMfaHighAddr);
6720 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6721 ioc->facts.CurrentSenseBufferHighAddr);
6722
6723 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6724 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6725
6726 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6727 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6728 /*
6729 * Rounding UP to nearest 4-kB boundary here...
6730 */
6731 sz = (ioc->req_sz * ioc->req_depth) + 128;
6732 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6733 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6734 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6735 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6736 4*ioc->facts.RequestFrameSize,
6737 ioc->facts.GlobalCredits);
6738
6739 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6740 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6741 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6742 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6743 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6744 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6745 ioc->facts.CurReplyFrameSize,
6746 ioc->facts.ReplyQueueDepth);
6747
6748 len += sprintf(buf+len, " MaxDevices = %d\n",
6749 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6750 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6751
6752 /* per-port info */
6753 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6754 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6755 p+1,
6756 ioc->facts.NumberOfPorts);
6757 if (ioc->bus_type == FC) {
6758 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6759 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6760 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6761 a[5], a[4], a[3], a[2], a[1], a[0]);
6762 }
6763 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6764 ioc->fc_port_page0[p].WWNN.High,
6765 ioc->fc_port_page0[p].WWNN.Low,
6766 ioc->fc_port_page0[p].WWPN.High,
6767 ioc->fc_port_page0[p].WWPN.Low);
6768 }
6769 }
6770
6771 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6772}
6773
6774#endif /* CONFIG_PROC_FS } */
6775
6776/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6777static void
6778mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6779{
6780 buf[0] ='\0';
6781 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6782 sprintf(buf, " (Exp %02d%02d)",
6783 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6784 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6785
6786 /* insider hack! */
6787 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6788 strcat(buf, " [MDBG]");
6789 }
6790}
6791
6792/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6793/**
6794 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6795 * @ioc: Pointer to MPT_ADAPTER structure
6796 * @buffer: Pointer to buffer where IOC summary info should be written
6797 * @size: Pointer to number of bytes we wrote (set by this routine)
6798 * @len: Offset at which to start writing in buffer
6799 * @showlan: Display LAN stuff?
6800 *
6801 * This routine writes (english readable) ASCII text, which represents
6802 * a summary of IOC information, to a buffer.
6803 */
6804void
6805mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6806{
6807 char expVer[32];
6808 int y;
6809
6810 mpt_get_fw_exp_ver(expVer, ioc);
6811
6812 /*
6813 * Shorter summary of attached ioc's...
6814 */
6815 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6816 ioc->name,
6817 ioc->prod_name,
6818 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6819 ioc->facts.FWVersion.Word,
6820 expVer,
6821 ioc->facts.NumberOfPorts,
6822 ioc->req_depth);
6823
6824 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6825 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6826 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6827 a[5], a[4], a[3], a[2], a[1], a[0]);
6828 }
6829
Linus Torvalds1da177e2005-04-16 15:20:36 -07006830 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006831
6832 if (!ioc->active)
6833 y += sprintf(buffer+len+y, " (disabled)");
6834
6835 y += sprintf(buffer+len+y, "\n");
6836
6837 *size = y;
6838}
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306839/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006840 * mpt_set_taskmgmt_in_progress_flag - set flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306841 * @ioc: Pointer to MPT_ADAPTER structure
6842 *
6843 * Returns 0 for SUCCESS or -1 if FAILED.
6844 *
6845 * If -1 is return, then it was not possible to set the flags
6846 **/
6847int
6848mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6849{
6850 unsigned long flags;
6851 int retval;
6852
6853 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6854 if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
6855 (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
6856 retval = -1;
6857 goto out;
6858 }
6859 retval = 0;
6860 ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306861 ioc->taskmgmt_quiesce_io = 1;
6862 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306863 ioc->alt_ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306864 ioc->alt_ioc->taskmgmt_quiesce_io = 1;
6865 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306866 out:
6867 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6868 return retval;
6869}
6870EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
6871
6872/**
Uwe Kleine-Koenig3dbda772009-07-23 08:31:31 +02006873 * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task management
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306874 * @ioc: Pointer to MPT_ADAPTER structure
6875 *
6876 **/
6877void
6878mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6879{
6880 unsigned long flags;
6881
6882 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6883 ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306884 ioc->taskmgmt_quiesce_io = 0;
6885 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306886 ioc->alt_ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306887 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
6888 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306889 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6890}
6891EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006892
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306893
6894/**
6895 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6896 * the kernel
6897 * @ioc: Pointer to MPT_ADAPTER structure
6898 *
6899 **/
6900void
6901mpt_halt_firmware(MPT_ADAPTER *ioc)
6902{
6903 u32 ioc_raw_state;
6904
6905 ioc_raw_state = mpt_GetIocState(ioc, 0);
6906
6907 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6908 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6909 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6910 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6911 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6912 } else {
6913 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6914 panic("%s: Firmware is halted due to command timeout\n",
6915 ioc->name);
6916 }
6917}
6918EXPORT_SYMBOL(mpt_halt_firmware);
6919
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306920/**
6921 * mpt_SoftResetHandler - Issues a less expensive reset
6922 * @ioc: Pointer to MPT_ADAPTER structure
6923 * @sleepFlag: Indicates if sleep or schedule must be called.
6924
6925 *
6926 * Returns 0 for SUCCESS or -1 if FAILED.
6927 *
6928 * Message Unit Reset - instructs the IOC to reset the Reply Post and
6929 * Free FIFO's. All the Message Frames on Reply Free FIFO are discarded.
6930 * All posted buffers are freed, and event notification is turned off.
6931 * IOC doesnt reply to any outstanding request. This will transfer IOC
6932 * to READY state.
6933 **/
6934int
6935mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6936{
6937 int rc;
6938 int ii;
6939 u8 cb_idx;
6940 unsigned long flags;
6941 u32 ioc_state;
6942 unsigned long time_count;
6943
6944 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n",
6945 ioc->name));
6946
6947 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
6948
6949 if (mpt_fwfault_debug)
6950 mpt_halt_firmware(ioc);
6951
6952 if (ioc_state == MPI_IOC_STATE_FAULT ||
6953 ioc_state == MPI_IOC_STATE_RESET) {
6954 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6955 "skipping, either in FAULT or RESET state!\n", ioc->name));
6956 return -1;
6957 }
6958
6959 if (ioc->bus_type == FC) {
6960 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6961 "skipping, because the bus type is FC!\n", ioc->name));
6962 return -1;
6963 }
6964
6965 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6966 if (ioc->ioc_reset_in_progress) {
6967 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6968 return -1;
6969 }
6970 ioc->ioc_reset_in_progress = 1;
6971 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6972
6973 rc = -1;
6974
6975 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6976 if (MptResetHandlers[cb_idx])
6977 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
6978 }
6979
6980 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6981 if (ioc->taskmgmt_in_progress) {
Kashyap, Desaib9a0f872010-06-17 14:42:39 +05306982 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05306983 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6984 return -1;
6985 }
6986 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6987 /* Disable reply interrupts (also blocks FreeQ) */
6988 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
6989 ioc->active = 0;
6990 time_count = jiffies;
6991
6992 rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
6993
6994 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6995 if (MptResetHandlers[cb_idx])
6996 mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
6997 }
6998
6999 if (rc)
7000 goto out;
7001
7002 ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
7003 if (ioc_state != MPI_IOC_STATE_READY)
7004 goto out;
7005
7006 for (ii = 0; ii < 5; ii++) {
7007 /* Get IOC facts! Allow 5 retries */
7008 rc = GetIocFacts(ioc, sleepFlag,
7009 MPT_HOSTEVENT_IOC_RECOVER);
7010 if (rc == 0)
7011 break;
7012 if (sleepFlag == CAN_SLEEP)
7013 msleep(100);
7014 else
7015 mdelay(100);
7016 }
7017 if (ii == 5)
7018 goto out;
7019
7020 rc = PrimeIocFifos(ioc);
7021 if (rc != 0)
7022 goto out;
7023
7024 rc = SendIocInit(ioc, sleepFlag);
7025 if (rc != 0)
7026 goto out;
7027
7028 rc = SendEventNotification(ioc, 1, sleepFlag);
7029 if (rc != 0)
7030 goto out;
7031
7032 if (ioc->hard_resets < -1)
7033 ioc->hard_resets++;
7034
7035 /*
7036 * At this point, we know soft reset succeeded.
7037 */
7038
7039 ioc->active = 1;
7040 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
7041
7042 out:
7043 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7044 ioc->ioc_reset_in_progress = 0;
7045 ioc->taskmgmt_quiesce_io = 0;
7046 ioc->taskmgmt_in_progress = 0;
7047 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
7048
7049 if (ioc->active) { /* otherwise, hard reset coming */
7050 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7051 if (MptResetHandlers[cb_idx])
7052 mpt_signal_reset(cb_idx, ioc,
7053 MPT_IOC_POST_RESET);
7054 }
7055 }
7056
7057 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7058 "SoftResetHandler: completed (%d seconds): %s\n",
7059 ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,
7060 ((rc == 0) ? "SUCCESS" : "FAILED")));
7061
7062 return rc;
7063}
7064
7065/**
7066 * mpt_Soft_Hard_ResetHandler - Try less expensive reset
7067 * @ioc: Pointer to MPT_ADAPTER structure
7068 * @sleepFlag: Indicates if sleep or schedule must be called.
7069
7070 *
7071 * Returns 0 for SUCCESS or -1 if FAILED.
7072 * Try for softreset first, only if it fails go for expensive
7073 * HardReset.
7074 **/
7075int
7076mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag) {
7077 int ret = -1;
7078
7079 ret = mpt_SoftResetHandler(ioc, sleepFlag);
7080 if (ret == 0)
7081 return ret;
7082 ret = mpt_HardResetHandler(ioc, sleepFlag);
7083 return ret;
7084}
7085EXPORT_SYMBOL(mpt_Soft_Hard_ResetHandler);
7086
Linus Torvalds1da177e2005-04-16 15:20:36 -07007087/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7088/*
7089 * Reset Handling
7090 */
7091/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
7092/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007093 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07007094 * @ioc: Pointer to MPT_ADAPTER structure
7095 * @sleepFlag: Indicates if sleep or schedule must be called.
7096 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007097 * Issues SCSI Task Management call based on input arg values.
7098 * If TaskMgmt fails, returns associated SCSI request.
7099 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07007100 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
7101 * or a non-interrupt thread. In the former, must not call schedule().
7102 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007103 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07007104 * FW reload/initialization failed.
7105 *
7106 * Returns 0 for SUCCESS or -1 if FAILED.
7107 */
7108int
7109mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
7110{
Kashyap, Desaid1306912009-08-05 12:53:51 +05307111 int rc;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307112 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007113 unsigned long flags;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307114 unsigned long time_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007115
Prakash, Sathya436ace72007-07-24 15:42:08 +05307116 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007117#ifdef MFCNT
7118 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
7119 printk("MF count 0x%x !\n", ioc->mfcnt);
7120#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05307121 if (mpt_fwfault_debug)
7122 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007123
7124 /* Reset the adapter. Prevent more than 1 call to
7125 * mpt_do_ioc_recovery at any instant in time.
7126 */
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307127 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7128 if (ioc->ioc_reset_in_progress) {
7129 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007130 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007131 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307132 ioc->ioc_reset_in_progress = 1;
7133 if (ioc->alt_ioc)
7134 ioc->alt_ioc->ioc_reset_in_progress = 1;
7135 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007136
Linus Torvalds1da177e2005-04-16 15:20:36 -07007137
7138 /* The SCSI driver needs to adjust timeouts on all current
7139 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02007140 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007141 * For all other protocol drivers, this is a no-op.
7142 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05307143 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7144 if (MptResetHandlers[cb_idx]) {
7145 mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
7146 if (ioc->alt_ioc)
7147 mpt_signal_reset(cb_idx, ioc->alt_ioc,
7148 MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007149 }
7150 }
7151
Kashyap, Desai2f187862009-05-29 16:52:37 +05307152 time_count = jiffies;
7153 rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag);
7154 if (rc != 0) {
7155 printk(KERN_WARNING MYNAM
Kei Tokunaga97009a22010-06-22 19:01:51 +09007156 ": WARNING - (%d) Cannot recover %s, doorbell=0x%08x\n",
7157 rc, ioc->name, mpt_GetIocState(ioc, 0));
Kashyap, Desai2f187862009-05-29 16:52:37 +05307158 } else {
7159 if (ioc->hard_resets < -1)
7160 ioc->hard_resets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007161 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007162
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307163 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
7164 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307165 ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307166 ioc->taskmgmt_in_progress = 0;
7167 if (ioc->alt_ioc) {
7168 ioc->alt_ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05307169 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05307170 ioc->alt_ioc->taskmgmt_in_progress = 0;
7171 }
7172 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007173
Kashyap, Desaid1306912009-08-05 12:53:51 +05307174 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
7175 if (MptResetHandlers[cb_idx]) {
7176 mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
7177 if (ioc->alt_ioc)
7178 mpt_signal_reset(cb_idx,
7179 ioc->alt_ioc, MPT_IOC_POST_RESET);
7180 }
7181 }
7182
Kashyap, Desai2f187862009-05-29 16:52:37 +05307183 dtmprintk(ioc,
7184 printk(MYIOC_s_DEBUG_FMT
7185 "HardResetHandler: completed (%d seconds): %s\n", ioc->name,
7186 jiffies_to_msecs(jiffies - time_count)/1000, ((rc == 0) ?
7187 "SUCCESS" : "FAILED")));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007188
7189 return rc;
7190}
7191
Kashyap, Desai2f187862009-05-29 16:52:37 +05307192#ifdef CONFIG_FUSION_LOGGING
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007193static void
Kashyap, Desai2f187862009-05-29 16:52:37 +05307194mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007195{
Eric Moore509e5e52006-04-26 13:22:37 -06007196 char *ds = NULL;
Kashyap, Desai2f187862009-05-29 16:52:37 +05307197 u32 evData0;
7198 int ii;
7199 u8 event;
7200 char *evStr = ioc->evStr;
7201
7202 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7203 evData0 = le32_to_cpu(pEventReply->Data[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007204
7205 switch(event) {
7206 case MPI_EVENT_NONE:
7207 ds = "None";
7208 break;
7209 case MPI_EVENT_LOG_DATA:
7210 ds = "Log Data";
7211 break;
7212 case MPI_EVENT_STATE_CHANGE:
7213 ds = "State Change";
7214 break;
7215 case MPI_EVENT_UNIT_ATTENTION:
7216 ds = "Unit Attention";
7217 break;
7218 case MPI_EVENT_IOC_BUS_RESET:
7219 ds = "IOC Bus Reset";
7220 break;
7221 case MPI_EVENT_EXT_BUS_RESET:
7222 ds = "External Bus Reset";
7223 break;
7224 case MPI_EVENT_RESCAN:
7225 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007226 break;
7227 case MPI_EVENT_LINK_STATUS_CHANGE:
7228 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
7229 ds = "Link Status(FAILURE) Change";
7230 else
7231 ds = "Link Status(ACTIVE) Change";
7232 break;
7233 case MPI_EVENT_LOOP_STATE_CHANGE:
7234 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
7235 ds = "Loop State(LIP) Change";
7236 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Kashyap, Desai2f187862009-05-29 16:52:37 +05307237 ds = "Loop State(LPE) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007238 else
Kashyap, Desai2f187862009-05-29 16:52:37 +05307239 ds = "Loop State(LPB) Change";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007240 break;
7241 case MPI_EVENT_LOGOUT:
7242 ds = "Logout";
7243 break;
7244 case MPI_EVENT_EVENT_CHANGE:
7245 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06007246 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007247 else
Eric Moore4f766dc2006-07-11 17:24:07 -06007248 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007249 break;
7250 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007251 {
7252 u8 ReasonCode = (u8)(evData0 >> 16);
7253 switch (ReasonCode) {
7254 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
7255 ds = "Integrated Raid: Volume Created";
7256 break;
7257 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
7258 ds = "Integrated Raid: Volume Deleted";
7259 break;
7260 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
7261 ds = "Integrated Raid: Volume Settings Changed";
7262 break;
7263 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
7264 ds = "Integrated Raid: Volume Status Changed";
7265 break;
7266 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
7267 ds = "Integrated Raid: Volume Physdisk Changed";
7268 break;
7269 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
7270 ds = "Integrated Raid: Physdisk Created";
7271 break;
7272 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
7273 ds = "Integrated Raid: Physdisk Deleted";
7274 break;
7275 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
7276 ds = "Integrated Raid: Physdisk Settings Changed";
7277 break;
7278 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
7279 ds = "Integrated Raid: Physdisk Status Changed";
7280 break;
7281 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
7282 ds = "Integrated Raid: Domain Validation Needed";
7283 break;
7284 case MPI_EVENT_RAID_RC_SMART_DATA :
7285 ds = "Integrated Raid; Smart Data";
7286 break;
7287 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
7288 ds = "Integrated Raid: Replace Action Started";
7289 break;
7290 default:
7291 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007292 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007293 }
7294 break;
7295 }
7296 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
7297 ds = "SCSI Device Status Change";
7298 break;
7299 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
7300 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007301 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007302 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007303 u8 ReasonCode = (u8)(evData0 >> 16);
7304 switch (ReasonCode) {
7305 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007306 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007307 "SAS Device Status Change: Added: "
7308 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007309 break;
7310 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06007311 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007312 "SAS Device Status Change: Deleted: "
7313 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007314 break;
7315 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06007316 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007317 "SAS Device Status Change: SMART Data: "
7318 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007319 break;
7320 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06007321 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007322 "SAS Device Status Change: No Persistancy: "
7323 "id=%d channel=%d", id, channel);
7324 break;
7325 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
7326 snprintf(evStr, EVENT_DESCR_STR_SZ,
7327 "SAS Device Status Change: Unsupported Device "
7328 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007329 break;
7330 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
7331 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007332 "SAS Device Status Change: Internal Device "
7333 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007334 break;
7335 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
7336 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007337 "SAS Device Status Change: Internal Task "
7338 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007339 break;
7340 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
7341 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007342 "SAS Device Status Change: Internal Abort "
7343 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007344 break;
7345 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
7346 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007347 "SAS Device Status Change: Internal Clear "
7348 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06007349 break;
7350 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
7351 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007352 "SAS Device Status Change: Internal Query "
7353 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007354 break;
7355 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007356 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07007357 "SAS Device Status Change: Unknown: "
7358 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06007359 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007360 }
7361 break;
7362 }
7363 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
7364 ds = "Bus Timer Expired";
7365 break;
7366 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07007367 {
7368 u16 curr_depth = (u16)(evData0 >> 16);
7369 u8 channel = (u8)(evData0 >> 8);
7370 u8 id = (u8)(evData0);
7371
7372 snprintf(evStr, EVENT_DESCR_STR_SZ,
7373 "Queue Full: channel=%d id=%d depth=%d",
7374 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007375 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07007376 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007377 case MPI_EVENT_SAS_SES:
7378 ds = "SAS SES Event";
7379 break;
7380 case MPI_EVENT_PERSISTENT_TABLE_FULL:
7381 ds = "Persistent Table Full";
7382 break;
7383 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07007384 {
Moore, Eric3a892be2006-03-14 09:14:03 -07007385 u8 LinkRates = (u8)(evData0 >> 8);
7386 u8 PhyNumber = (u8)(evData0);
7387 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
7388 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
7389 switch (LinkRates) {
7390 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06007391 snprintf(evStr, EVENT_DESCR_STR_SZ,
7392 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007393 " Rate Unknown",PhyNumber);
7394 break;
7395 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06007396 snprintf(evStr, EVENT_DESCR_STR_SZ,
7397 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007398 " Phy Disabled",PhyNumber);
7399 break;
7400 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06007401 snprintf(evStr, EVENT_DESCR_STR_SZ,
7402 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007403 " Failed Speed Nego",PhyNumber);
7404 break;
7405 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06007406 snprintf(evStr, EVENT_DESCR_STR_SZ,
7407 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007408 " Sata OOB Completed",PhyNumber);
7409 break;
7410 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06007411 snprintf(evStr, EVENT_DESCR_STR_SZ,
7412 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007413 " Rate 1.5 Gbps",PhyNumber);
7414 break;
7415 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06007416 snprintf(evStr, EVENT_DESCR_STR_SZ,
7417 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07007418 " Rate 3.0 Gpbs",PhyNumber);
7419 break;
7420 default:
Eric Moore509e5e52006-04-26 13:22:37 -06007421 snprintf(evStr, EVENT_DESCR_STR_SZ,
7422 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07007423 break;
7424 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007425 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007426 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007427 case MPI_EVENT_SAS_DISCOVERY_ERROR:
7428 ds = "SAS Discovery Error";
7429 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007430 case MPI_EVENT_IR_RESYNC_UPDATE:
7431 {
7432 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06007433 snprintf(evStr, EVENT_DESCR_STR_SZ,
7434 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07007435 break;
7436 }
7437 case MPI_EVENT_IR2:
7438 {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307439 u8 id = (u8)(evData0);
7440 u8 channel = (u8)(evData0 >> 8);
7441 u8 phys_num = (u8)(evData0 >> 24);
Moore, Eric3a892be2006-03-14 09:14:03 -07007442 u8 ReasonCode = (u8)(evData0 >> 16);
Kashyap, Desai2f187862009-05-29 16:52:37 +05307443
Moore, Eric3a892be2006-03-14 09:14:03 -07007444 switch (ReasonCode) {
7445 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307446 snprintf(evStr, EVENT_DESCR_STR_SZ,
7447 "IR2: LD State Changed: "
7448 "id=%d channel=%d phys_num=%d",
7449 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007450 break;
7451 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307452 snprintf(evStr, EVENT_DESCR_STR_SZ,
7453 "IR2: PD State Changed "
7454 "id=%d channel=%d phys_num=%d",
7455 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007456 break;
7457 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307458 snprintf(evStr, EVENT_DESCR_STR_SZ,
7459 "IR2: Bad Block Table Full: "
7460 "id=%d channel=%d phys_num=%d",
7461 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007462 break;
7463 case MPI_EVENT_IR2_RC_PD_INSERTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307464 snprintf(evStr, EVENT_DESCR_STR_SZ,
7465 "IR2: PD Inserted: "
7466 "id=%d channel=%d phys_num=%d",
7467 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007468 break;
7469 case MPI_EVENT_IR2_RC_PD_REMOVED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307470 snprintf(evStr, EVENT_DESCR_STR_SZ,
7471 "IR2: PD Removed: "
7472 "id=%d channel=%d phys_num=%d",
7473 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007474 break;
7475 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307476 snprintf(evStr, EVENT_DESCR_STR_SZ,
7477 "IR2: Foreign CFG Detected: "
7478 "id=%d channel=%d phys_num=%d",
7479 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007480 break;
7481 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
Kashyap, Desai2f187862009-05-29 16:52:37 +05307482 snprintf(evStr, EVENT_DESCR_STR_SZ,
7483 "IR2: Rebuild Medium Error: "
7484 "id=%d channel=%d phys_num=%d",
7485 id, channel, phys_num);
Moore, Eric3a892be2006-03-14 09:14:03 -07007486 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05307487 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
7488 snprintf(evStr, EVENT_DESCR_STR_SZ,
7489 "IR2: Dual Port Added: "
7490 "id=%d channel=%d phys_num=%d",
7491 id, channel, phys_num);
7492 break;
7493 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
7494 snprintf(evStr, EVENT_DESCR_STR_SZ,
7495 "IR2: Dual Port Removed: "
7496 "id=%d channel=%d phys_num=%d",
7497 id, channel, phys_num);
7498 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07007499 default:
7500 ds = "IR2";
7501 break;
7502 }
7503 break;
7504 }
7505 case MPI_EVENT_SAS_DISCOVERY:
7506 {
7507 if (evData0)
7508 ds = "SAS Discovery: Start";
7509 else
7510 ds = "SAS Discovery: Stop";
7511 break;
7512 }
7513 case MPI_EVENT_LOG_ENTRY_ADDED:
7514 ds = "SAS Log Entry Added";
7515 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007516
Eric Moorec6c727a2007-01-29 09:44:54 -07007517 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
7518 {
7519 u8 phy_num = (u8)(evData0);
7520 u8 port_num = (u8)(evData0 >> 8);
7521 u8 port_width = (u8)(evData0 >> 16);
7522 u8 primative = (u8)(evData0 >> 24);
7523 snprintf(evStr, EVENT_DESCR_STR_SZ,
7524 "SAS Broadcase Primative: phy=%d port=%d "
7525 "width=%d primative=0x%02x",
7526 phy_num, port_num, port_width, primative);
7527 break;
7528 }
7529
7530 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7531 {
7532 u8 reason = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07007533
Kashyap, Desai2f187862009-05-29 16:52:37 +05307534 switch (reason) {
7535 case MPI_EVENT_SAS_INIT_RC_ADDED:
7536 ds = "SAS Initiator Status Change: Added";
7537 break;
7538 case MPI_EVENT_SAS_INIT_RC_REMOVED:
7539 ds = "SAS Initiator Status Change: Deleted";
7540 break;
7541 default:
7542 ds = "SAS Initiator Status Change";
7543 break;
7544 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007545 break;
7546 }
7547
7548 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7549 {
7550 u8 max_init = (u8)(evData0);
7551 u8 current_init = (u8)(evData0 >> 8);
7552
7553 snprintf(evStr, EVENT_DESCR_STR_SZ,
7554 "SAS Initiator Device Table Overflow: max initiators=%02d "
7555 "current initators=%02d",
7556 max_init, current_init);
7557 break;
7558 }
7559 case MPI_EVENT_SAS_SMP_ERROR:
7560 {
7561 u8 status = (u8)(evData0);
7562 u8 port_num = (u8)(evData0 >> 8);
7563 u8 result = (u8)(evData0 >> 16);
7564
7565 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7566 snprintf(evStr, EVENT_DESCR_STR_SZ,
7567 "SAS SMP Error: port=%d result=0x%02x",
7568 port_num, result);
7569 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7570 snprintf(evStr, EVENT_DESCR_STR_SZ,
7571 "SAS SMP Error: port=%d : CRC Error",
7572 port_num);
7573 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7574 snprintf(evStr, EVENT_DESCR_STR_SZ,
7575 "SAS SMP Error: port=%d : Timeout",
7576 port_num);
7577 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7578 snprintf(evStr, EVENT_DESCR_STR_SZ,
7579 "SAS SMP Error: port=%d : No Destination",
7580 port_num);
7581 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7582 snprintf(evStr, EVENT_DESCR_STR_SZ,
7583 "SAS SMP Error: port=%d : Bad Destination",
7584 port_num);
7585 else
7586 snprintf(evStr, EVENT_DESCR_STR_SZ,
7587 "SAS SMP Error: port=%d : status=0x%02x",
7588 port_num, status);
7589 break;
7590 }
7591
Kashyap, Desai2f187862009-05-29 16:52:37 +05307592 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
7593 {
7594 u8 reason = (u8)(evData0);
7595
7596 switch (reason) {
7597 case MPI_EVENT_SAS_EXP_RC_ADDED:
7598 ds = "Expander Status Change: Added";
7599 break;
7600 case MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING:
7601 ds = "Expander Status Change: Deleted";
7602 break;
7603 default:
7604 ds = "Expander Status Change";
7605 break;
7606 }
7607 break;
7608 }
7609
Linus Torvalds1da177e2005-04-16 15:20:36 -07007610 /*
7611 * MPT base "custom" events may be added here...
7612 */
7613 default:
7614 ds = "Unknown";
7615 break;
7616 }
Eric Moore509e5e52006-04-26 13:22:37 -06007617 if (ds)
7618 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007619
Kashyap, Desai2f187862009-05-29 16:52:37 +05307620
7621 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7622 "MPT event:(%02Xh) : %s\n",
7623 ioc->name, event, evStr));
7624
7625 devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
7626 ": Event data:\n"));
7627 for (ii = 0; ii < le16_to_cpu(pEventReply->EventDataLength); ii++)
7628 devtverboseprintk(ioc, printk(" %08x",
7629 le32_to_cpu(pEventReply->Data[ii])));
7630 devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
7631}
7632#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007633/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007634/**
7635 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007636 * @ioc: Pointer to MPT_ADAPTER structure
7637 * @pEventReply: Pointer to EventNotification reply frame
7638 * @evHandlers: Pointer to integer, number of event handlers
7639 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007640 * Routes a received EventNotificationReply to all currently registered
7641 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007642 * Returns sum of event handlers return values.
7643 */
7644static int
7645ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7646{
7647 u16 evDataLen;
7648 u32 evData0 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007649 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307650 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007651 int r = 0;
7652 int handlers = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007653 u8 event;
7654
7655 /*
7656 * Do platform normalization of values
7657 */
7658 event = le32_to_cpu(pEventReply->Event) & 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007659 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7660 if (evDataLen) {
7661 evData0 = le32_to_cpu(pEventReply->Data[0]);
7662 }
7663
Prakash, Sathya436ace72007-07-24 15:42:08 +05307664#ifdef CONFIG_FUSION_LOGGING
Kashyap, Desai2f187862009-05-29 16:52:37 +05307665 if (evDataLen)
7666 mpt_display_event_info(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007667#endif
7668
7669 /*
7670 * Do general / base driver event processing
7671 */
7672 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007673 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7674 if (evDataLen) {
7675 u8 evState = evData0 & 0xFF;
7676
7677 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7678
7679 /* Update EventState field in cached IocFacts */
7680 if (ioc->facts.Function) {
7681 ioc->facts.EventState = evState;
7682 }
7683 }
7684 break;
Moore, Ericece50912006-01-16 18:53:19 -07007685 case MPI_EVENT_INTEGRATED_RAID:
7686 mptbase_raid_process_event_data(ioc,
7687 (MpiEventDataRaid_t *)pEventReply->Data);
7688 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007689 default:
7690 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007691 }
7692
7693 /*
7694 * Should this event be logged? Events are written sequentially.
7695 * When buffer is full, start again at the top.
7696 */
7697 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7698 int idx;
7699
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007700 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007701
7702 ioc->events[idx].event = event;
7703 ioc->events[idx].eventContext = ioc->eventContext;
7704
7705 for (ii = 0; ii < 2; ii++) {
7706 if (ii < evDataLen)
7707 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7708 else
7709 ioc->events[idx].data[ii] = 0;
7710 }
7711
7712 ioc->eventContext++;
7713 }
7714
7715
7716 /*
7717 * Call each currently registered protocol event handler.
7718 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007719 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307720 if (MptEvHandlers[cb_idx]) {
Kashyap, Desai2f187862009-05-29 16:52:37 +05307721 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7722 "Routing Event to event handler #%d\n",
7723 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307724 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007725 handlers++;
7726 }
7727 }
7728 /* FIXME? Examine results here? */
7729
7730 /*
7731 * If needed, send (a single) EventAck.
7732 */
7733 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307734 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007735 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007736 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307737 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007738 ioc->name, ii));
7739 }
7740 }
7741
7742 *evHandlers = handlers;
7743 return r;
7744}
7745
7746/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007747/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007748 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7749 * @ioc: Pointer to MPT_ADAPTER structure
7750 * @log_info: U32 LogInfo reply word from the IOC
7751 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007752 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007753 */
7754static void
7755mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7756{
Eric Moore7c431e52007-06-13 16:34:36 -06007757 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007758
Eric Moore7c431e52007-06-13 16:34:36 -06007759 switch (log_info & 0xFF000000) {
7760 case MPI_IOCLOGINFO_FC_INIT_BASE:
7761 desc = "FCP Initiator";
7762 break;
7763 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7764 desc = "FCP Target";
7765 break;
7766 case MPI_IOCLOGINFO_FC_LAN_BASE:
7767 desc = "LAN";
7768 break;
7769 case MPI_IOCLOGINFO_FC_MSG_BASE:
7770 desc = "MPI Message Layer";
7771 break;
7772 case MPI_IOCLOGINFO_FC_LINK_BASE:
7773 desc = "FC Link";
7774 break;
7775 case MPI_IOCLOGINFO_FC_CTX_BASE:
7776 desc = "Context Manager";
7777 break;
7778 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7779 desc = "Invalid Field Offset";
7780 break;
7781 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7782 desc = "State Change Info";
7783 break;
7784 }
7785
7786 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7787 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007788}
7789
7790/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007791/**
Moore, Eric335a9412006-01-17 17:06:23 -07007792 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007793 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007794 * @log_info: U32 LogInfo word from the IOC
7795 *
7796 * Refer to lsi/sp_log.h.
7797 */
7798static void
Moore, Eric335a9412006-01-17 17:06:23 -07007799mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007800{
7801 u32 info = log_info & 0x00FF0000;
7802 char *desc = "unknown";
7803
7804 switch (info) {
7805 case 0x00010000:
7806 desc = "bug! MID not found";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007807 break;
7808
7809 case 0x00020000:
7810 desc = "Parity Error";
7811 break;
7812
7813 case 0x00030000:
7814 desc = "ASYNC Outbound Overrun";
7815 break;
7816
7817 case 0x00040000:
7818 desc = "SYNC Offset Error";
7819 break;
7820
7821 case 0x00050000:
7822 desc = "BM Change";
7823 break;
7824
7825 case 0x00060000:
7826 desc = "Msg In Overflow";
7827 break;
7828
7829 case 0x00070000:
7830 desc = "DMA Error";
7831 break;
7832
7833 case 0x00080000:
7834 desc = "Outbound DMA Overrun";
7835 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007836
Linus Torvalds1da177e2005-04-16 15:20:36 -07007837 case 0x00090000:
7838 desc = "Task Management";
7839 break;
7840
7841 case 0x000A0000:
7842 desc = "Device Problem";
7843 break;
7844
7845 case 0x000B0000:
7846 desc = "Invalid Phase Change";
7847 break;
7848
7849 case 0x000C0000:
7850 desc = "Untagged Table Size";
7851 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007852
Linus Torvalds1da177e2005-04-16 15:20:36 -07007853 }
7854
7855 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7856}
7857
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007858/* strings for sas loginfo */
7859 static char *originator_str[] = {
7860 "IOP", /* 00h */
7861 "PL", /* 01h */
7862 "IR" /* 02h */
7863 };
7864 static char *iop_code_str[] = {
7865 NULL, /* 00h */
7866 "Invalid SAS Address", /* 01h */
7867 NULL, /* 02h */
7868 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007869 "Diag Message Error", /* 04h */
7870 "Task Terminated", /* 05h */
7871 "Enclosure Management", /* 06h */
7872 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007873 };
7874 static char *pl_code_str[] = {
7875 NULL, /* 00h */
7876 "Open Failure", /* 01h */
7877 "Invalid Scatter Gather List", /* 02h */
7878 "Wrong Relative Offset or Frame Length", /* 03h */
7879 "Frame Transfer Error", /* 04h */
7880 "Transmit Frame Connected Low", /* 05h */
7881 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7882 "SATA Read Log Receive Data Error", /* 07h */
7883 "SATA NCQ Fail All Commands After Error", /* 08h */
7884 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7885 "Receive Frame Invalid Message", /* 0Ah */
7886 "Receive Context Message Valid Error", /* 0Bh */
7887 "Receive Frame Current Frame Error", /* 0Ch */
7888 "SATA Link Down", /* 0Dh */
7889 "Discovery SATA Init W IOS", /* 0Eh */
7890 "Config Invalid Page", /* 0Fh */
7891 "Discovery SATA Init Timeout", /* 10h */
7892 "Reset", /* 11h */
7893 "Abort", /* 12h */
7894 "IO Not Yet Executed", /* 13h */
7895 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007896 "Persistent Reservation Out Not Affiliation "
7897 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007898 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007899 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007900 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007901 NULL, /* 19h */
7902 NULL, /* 1Ah */
7903 NULL, /* 1Bh */
7904 NULL, /* 1Ch */
7905 NULL, /* 1Dh */
7906 NULL, /* 1Eh */
7907 NULL, /* 1Fh */
7908 "Enclosure Management" /* 20h */
7909 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007910 static char *ir_code_str[] = {
7911 "Raid Action Error", /* 00h */
7912 NULL, /* 00h */
7913 NULL, /* 01h */
7914 NULL, /* 02h */
7915 NULL, /* 03h */
7916 NULL, /* 04h */
7917 NULL, /* 05h */
7918 NULL, /* 06h */
7919 NULL /* 07h */
7920 };
7921 static char *raid_sub_code_str[] = {
7922 NULL, /* 00h */
7923 "Volume Creation Failed: Data Passed too "
7924 "Large", /* 01h */
7925 "Volume Creation Failed: Duplicate Volumes "
7926 "Attempted", /* 02h */
7927 "Volume Creation Failed: Max Number "
7928 "Supported Volumes Exceeded", /* 03h */
7929 "Volume Creation Failed: DMA Error", /* 04h */
7930 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7931 "Volume Creation Failed: Error Reading "
7932 "MFG Page 4", /* 06h */
7933 "Volume Creation Failed: Creating Internal "
7934 "Structures", /* 07h */
7935 NULL, /* 08h */
7936 NULL, /* 09h */
7937 NULL, /* 0Ah */
7938 NULL, /* 0Bh */
7939 NULL, /* 0Ch */
7940 NULL, /* 0Dh */
7941 NULL, /* 0Eh */
7942 NULL, /* 0Fh */
7943 "Activation failed: Already Active Volume", /* 10h */
7944 "Activation failed: Unsupported Volume Type", /* 11h */
7945 "Activation failed: Too Many Active Volumes", /* 12h */
7946 "Activation failed: Volume ID in Use", /* 13h */
7947 "Activation failed: Reported Failure", /* 14h */
7948 "Activation failed: Importing a Volume", /* 15h */
7949 NULL, /* 16h */
7950 NULL, /* 17h */
7951 NULL, /* 18h */
7952 NULL, /* 19h */
7953 NULL, /* 1Ah */
7954 NULL, /* 1Bh */
7955 NULL, /* 1Ch */
7956 NULL, /* 1Dh */
7957 NULL, /* 1Eh */
7958 NULL, /* 1Fh */
7959 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7960 "Phys Disk failed: Data Passed too Large", /* 21h */
7961 "Phys Disk failed: DMA Error", /* 22h */
7962 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7963 "Phys Disk failed: Creating Phys Disk Config "
7964 "Page", /* 24h */
7965 NULL, /* 25h */
7966 NULL, /* 26h */
7967 NULL, /* 27h */
7968 NULL, /* 28h */
7969 NULL, /* 29h */
7970 NULL, /* 2Ah */
7971 NULL, /* 2Bh */
7972 NULL, /* 2Ch */
7973 NULL, /* 2Dh */
7974 NULL, /* 2Eh */
7975 NULL, /* 2Fh */
7976 "Compatibility Error: IR Disabled", /* 30h */
7977 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7978 "Compatibility Error: Device not Direct Access "
7979 "Device ", /* 32h */
7980 "Compatibility Error: Removable Device Found", /* 33h */
7981 "Compatibility Error: Device SCSI Version not "
7982 "2 or Higher", /* 34h */
7983 "Compatibility Error: SATA Device, 48 BIT LBA "
7984 "not Supported", /* 35h */
7985 "Compatibility Error: Device doesn't have "
7986 "512 Byte Block Sizes", /* 36h */
7987 "Compatibility Error: Volume Type Check Failed", /* 37h */
7988 "Compatibility Error: Volume Type is "
7989 "Unsupported by FW", /* 38h */
7990 "Compatibility Error: Disk Drive too Small for "
7991 "use in Volume", /* 39h */
7992 "Compatibility Error: Phys Disk for Create "
7993 "Volume not Found", /* 3Ah */
7994 "Compatibility Error: Too Many or too Few "
7995 "Disks for Volume Type", /* 3Bh */
7996 "Compatibility Error: Disk stripe Sizes "
7997 "Must be 64KB", /* 3Ch */
7998 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7999 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008000
8001/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008002/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008003 * mpt_sas_log_info - Log information returned from SAS IOC.
8004 * @ioc: Pointer to MPT_ADAPTER structure
8005 * @log_info: U32 LogInfo reply word from the IOC
8006 *
8007 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008008 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008009static void
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308010mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info, u8 cb_idx)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008011{
8012union loginfo_type {
8013 u32 loginfo;
8014 struct {
8015 u32 subcode:16;
8016 u32 code:8;
8017 u32 originator:4;
8018 u32 bus_type:4;
8019 }dw;
8020};
8021 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07008022 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008023 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07008024 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008025
8026 sas_loginfo.loginfo = log_info;
8027 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008028 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008029 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07008030
8031 originator_desc = originator_str[sas_loginfo.dw.originator];
8032
8033 switch (sas_loginfo.dw.originator) {
8034
8035 case 0: /* IOP */
8036 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008037 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008038 code_desc = iop_code_str[sas_loginfo.dw.code];
8039 break;
8040 case 1: /* PL */
8041 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008042 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008043 code_desc = pl_code_str[sas_loginfo.dw.code];
8044 break;
8045 case 2: /* IR */
8046 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008047 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008048 break;
8049 code_desc = ir_code_str[sas_loginfo.dw.code];
8050 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01008051 ARRAY_SIZE(raid_sub_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07008052 break;
8053 if (sas_loginfo.dw.code == 0)
8054 sub_code_desc =
8055 raid_sub_code_str[sas_loginfo.dw.subcode];
8056 break;
8057 default:
8058 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008059 }
8060
Eric Moorec6c727a2007-01-29 09:44:54 -07008061 if (sub_code_desc != NULL)
8062 printk(MYIOC_s_INFO_FMT
8063 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308064 " SubCode={%s} cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008065 ioc->name, log_info, originator_desc, code_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308066 sub_code_desc, MptCallbacksName[cb_idx]);
Eric Moorec6c727a2007-01-29 09:44:54 -07008067 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008068 printk(MYIOC_s_INFO_FMT
8069 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308070 " SubCode(0x%04x) cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008071 ioc->name, log_info, originator_desc, code_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308072 sas_loginfo.dw.subcode, MptCallbacksName[cb_idx]);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008073 else
8074 printk(MYIOC_s_INFO_FMT
8075 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308076 " SubCode(0x%04x) cb_idx %s\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07008077 ioc->name, log_info, originator_desc,
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308078 sas_loginfo.dw.code, sas_loginfo.dw.subcode,
8079 MptCallbacksName[cb_idx]);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06008080}
8081
Linus Torvalds1da177e2005-04-16 15:20:36 -07008082/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008083/**
Eric Moorec6c727a2007-01-29 09:44:54 -07008084 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
8085 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08008086 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07008087 * @mf: Pointer to MPT request frame
8088 *
8089 * Refer to lsi/mpi.h.
8090 **/
8091static void
8092mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
8093{
8094 Config_t *pReq = (Config_t *)mf;
8095 char extend_desc[EVENT_DESCR_STR_SZ];
8096 char *desc = NULL;
8097 u32 form;
8098 u8 page_type;
8099
8100 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
8101 page_type = pReq->ExtPageType;
8102 else
8103 page_type = pReq->Header.PageType;
8104
8105 /*
8106 * ignore invalid page messages for GET_NEXT_HANDLE
8107 */
8108 form = le32_to_cpu(pReq->PageAddress);
8109 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
8110 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
8111 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
8112 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
8113 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
8114 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
8115 return;
8116 }
8117 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
8118 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
8119 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
8120 return;
8121 }
8122
8123 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
8124 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
8125 page_type, pReq->Header.PageNumber, pReq->Action, form);
8126
8127 switch (ioc_status) {
8128
8129 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8130 desc = "Config Page Invalid Action";
8131 break;
8132
8133 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8134 desc = "Config Page Invalid Type";
8135 break;
8136
8137 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8138 desc = "Config Page Invalid Page";
8139 break;
8140
8141 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8142 desc = "Config Page Invalid Data";
8143 break;
8144
8145 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8146 desc = "Config Page No Defaults";
8147 break;
8148
8149 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
8150 desc = "Config Page Can't Commit";
8151 break;
8152 }
8153
8154 if (!desc)
8155 return;
8156
Eric Moore29dd3602007-09-14 18:46:51 -06008157 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
8158 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07008159}
8160
8161/**
8162 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07008163 * @ioc: Pointer to MPT_ADAPTER structure
8164 * @ioc_status: U32 IOCStatus word from IOC
8165 * @mf: Pointer to MPT request frame
8166 *
8167 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07008168 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07008169static void
Eric Moorec6c727a2007-01-29 09:44:54 -07008170mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008171{
8172 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06008173 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008174
8175 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07008176
8177/****************************************************************************/
8178/* Common IOCStatus values for all replies */
8179/****************************************************************************/
8180
Linus Torvalds1da177e2005-04-16 15:20:36 -07008181 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
8182 desc = "Invalid Function";
8183 break;
8184
8185 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
8186 desc = "Busy";
8187 break;
8188
8189 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
8190 desc = "Invalid SGL";
8191 break;
8192
8193 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
8194 desc = "Internal Error";
8195 break;
8196
8197 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
8198 desc = "Reserved";
8199 break;
8200
8201 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
8202 desc = "Insufficient Resources";
8203 break;
8204
8205 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
8206 desc = "Invalid Field";
8207 break;
8208
8209 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
8210 desc = "Invalid State";
8211 break;
8212
Eric Moorec6c727a2007-01-29 09:44:54 -07008213/****************************************************************************/
8214/* Config IOCStatus values */
8215/****************************************************************************/
8216
Linus Torvalds1da177e2005-04-16 15:20:36 -07008217 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
8218 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
8219 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
8220 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
8221 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
8222 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008223 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008224 break;
8225
Eric Moorec6c727a2007-01-29 09:44:54 -07008226/****************************************************************************/
8227/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
8228/* */
8229/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
8230/* */
8231/****************************************************************************/
8232
Linus Torvalds1da177e2005-04-16 15:20:36 -07008233 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008234 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07008235 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
8236 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
8237 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
8238 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008239 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008240 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008241 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008242 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008243 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008244 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07008245 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008246 break;
8247
Eric Moorec6c727a2007-01-29 09:44:54 -07008248/****************************************************************************/
8249/* SCSI Target values */
8250/****************************************************************************/
8251
8252 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
8253 desc = "Target: Priority IO";
8254 break;
8255
8256 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
8257 desc = "Target: Invalid Port";
8258 break;
8259
8260 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
8261 desc = "Target Invalid IO Index:";
8262 break;
8263
8264 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
8265 desc = "Target: Aborted";
8266 break;
8267
8268 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
8269 desc = "Target: No Conn Retryable";
8270 break;
8271
8272 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
8273 desc = "Target: No Connection";
8274 break;
8275
8276 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
8277 desc = "Target: Transfer Count Mismatch";
8278 break;
8279
8280 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
8281 desc = "Target: STS Data not Sent";
8282 break;
8283
8284 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
8285 desc = "Target: Data Offset Error";
8286 break;
8287
8288 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
8289 desc = "Target: Too Much Write Data";
8290 break;
8291
8292 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
8293 desc = "Target: IU Too Short";
8294 break;
8295
8296 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
8297 desc = "Target: ACK NAK Timeout";
8298 break;
8299
8300 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
8301 desc = "Target: Nak Received";
8302 break;
8303
8304/****************************************************************************/
8305/* Fibre Channel Direct Access values */
8306/****************************************************************************/
8307
8308 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
8309 desc = "FC: Aborted";
8310 break;
8311
8312 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
8313 desc = "FC: RX ID Invalid";
8314 break;
8315
8316 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
8317 desc = "FC: DID Invalid";
8318 break;
8319
8320 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
8321 desc = "FC: Node Logged Out";
8322 break;
8323
8324 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
8325 desc = "FC: Exchange Canceled";
8326 break;
8327
8328/****************************************************************************/
8329/* LAN values */
8330/****************************************************************************/
8331
8332 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
8333 desc = "LAN: Device not Found";
8334 break;
8335
8336 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
8337 desc = "LAN: Device Failure";
8338 break;
8339
8340 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
8341 desc = "LAN: Transmit Error";
8342 break;
8343
8344 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
8345 desc = "LAN: Transmit Aborted";
8346 break;
8347
8348 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
8349 desc = "LAN: Receive Error";
8350 break;
8351
8352 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
8353 desc = "LAN: Receive Aborted";
8354 break;
8355
8356 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
8357 desc = "LAN: Partial Packet";
8358 break;
8359
8360 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
8361 desc = "LAN: Canceled";
8362 break;
8363
8364/****************************************************************************/
8365/* Serial Attached SCSI values */
8366/****************************************************************************/
8367
8368 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
8369 desc = "SAS: SMP Request Failed";
8370 break;
8371
8372 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
8373 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07008374 break;
8375
8376 default:
8377 desc = "Others";
8378 break;
8379 }
Eric Moorec6c727a2007-01-29 09:44:54 -07008380
8381 if (!desc)
8382 return;
8383
Eric Moore29dd3602007-09-14 18:46:51 -06008384 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
8385 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008386}
8387
8388/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008389EXPORT_SYMBOL(mpt_attach);
8390EXPORT_SYMBOL(mpt_detach);
8391#ifdef CONFIG_PM
8392EXPORT_SYMBOL(mpt_resume);
8393EXPORT_SYMBOL(mpt_suspend);
8394#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07008395EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008396EXPORT_SYMBOL(mpt_register);
8397EXPORT_SYMBOL(mpt_deregister);
8398EXPORT_SYMBOL(mpt_event_register);
8399EXPORT_SYMBOL(mpt_event_deregister);
8400EXPORT_SYMBOL(mpt_reset_register);
8401EXPORT_SYMBOL(mpt_reset_deregister);
8402EXPORT_SYMBOL(mpt_device_driver_register);
8403EXPORT_SYMBOL(mpt_device_driver_deregister);
8404EXPORT_SYMBOL(mpt_get_msg_frame);
8405EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05308406EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008407EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008408EXPORT_SYMBOL(mpt_send_handshake_request);
8409EXPORT_SYMBOL(mpt_verify_adapter);
8410EXPORT_SYMBOL(mpt_GetIocState);
8411EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008412EXPORT_SYMBOL(mpt_HardResetHandler);
8413EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008414EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008415EXPORT_SYMBOL(mpt_alloc_fw_memory);
8416EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02008417EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07008418EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008419
Linus Torvalds1da177e2005-04-16 15:20:36 -07008420/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008421/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008422 * fusion_init - Fusion MPT base driver initialization routine.
8423 *
8424 * Returns 0 for success, non-zero for failure.
8425 */
8426static int __init
8427fusion_init(void)
8428{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308429 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008430
8431 show_mptmod_ver(my_NAME, my_VERSION);
8432 printk(KERN_INFO COPYRIGHT "\n");
8433
Prakash, Sathyaf606f572007-08-14 16:12:53 +05308434 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
8435 MptCallbacks[cb_idx] = NULL;
8436 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
8437 MptEvHandlers[cb_idx] = NULL;
8438 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008439 }
8440
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008441 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07008442 * EventNotification handling.
8443 */
Kashyap, Desai213aaca2010-07-26 18:57:36 +05308444 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER,
8445 "mptbase_reply");
Linus Torvalds1da177e2005-04-16 15:20:36 -07008446
8447 /* Register for hard reset handling callbacks.
8448 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05308449 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008450
8451#ifdef CONFIG_PROC_FS
8452 (void) procmpt_create();
8453#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04008454 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008455}
8456
8457/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08008458/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07008459 * fusion_exit - Perform driver unload cleanup.
8460 *
8461 * This routine frees all resources associated with each MPT adapter
8462 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
8463 */
8464static void __exit
8465fusion_exit(void)
8466{
8467
Linus Torvalds1da177e2005-04-16 15:20:36 -07008468 mpt_reset_deregister(mpt_base_index);
8469
8470#ifdef CONFIG_PROC_FS
8471 procmpt_destroy();
8472#endif
8473}
8474
Linus Torvalds1da177e2005-04-16 15:20:36 -07008475module_init(fusion_init);
8476module_exit(fusion_exit);