blob: ae203eca831f5cd71508b49745a77feee5b93989 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/message/fusion/mptbase.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * This is the Fusion MPT base driver which supports multiple
4 * (SCSI + LAN) specialized protocol drivers.
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05305 * For use with LSI PCI chip/adapter(s)
6 * running LSI Fusion MPT (Message Passing Technology) firmware.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
Prakash, Sathyacddc0ab2008-05-21 00:56:41 +05308 * Copyright (c) 1999-2008 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06009 * (mailto:DL-MPTFusionLinux@lsi.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
13/*
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; version 2 of the License.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 NO WARRANTY
24 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
25 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
26 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
27 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
28 solely responsible for determining the appropriateness of using and
29 distributing the Program and assumes all risks associated with its
30 exercise of rights under this Agreement, including but not limited to
31 the risks and costs of program errors, damage to or loss of data,
32 programs or equipment, and unavailability or interruption of operations.
33
34 DISCLAIMER OF LIABILITY
35 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
36 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
38 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
40 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
41 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
42
43 You should have received a copy of the GNU General Public License
44 along with this program; if not, write to the Free Software
45 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46*/
47/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/kernel.h>
50#include <linux/module.h>
51#include <linux/errno.h>
52#include <linux/init.h>
53#include <linux/slab.h>
54#include <linux/types.h>
55#include <linux/pci.h>
56#include <linux/kdev_t.h>
57#include <linux/blkdev.h>
58#include <linux/delay.h>
59#include <linux/interrupt.h> /* needed for in_interrupt() proto */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -040060#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include <asm/io.h>
62#ifdef CONFIG_MTRR
63#include <asm/mtrr.h>
64#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#include "mptbase.h"
Eric Moore7c431e52007-06-13 16:34:36 -060067#include "lsi/mpi_log_fc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
70#define my_NAME "Fusion MPT base driver"
71#define my_VERSION MPT_LINUX_VERSION_COMMON
72#define MYNAM "mptbase"
73
74MODULE_AUTHOR(MODULEAUTHOR);
75MODULE_DESCRIPTION(my_NAME);
76MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070077MODULE_VERSION(my_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/*
80 * cmd line parameters
81 */
Kashyap, Desaie3829682009-01-08 14:27:16 +053082
83static int mpt_msi_enable_spi;
84module_param(mpt_msi_enable_spi, int, 0);
85MODULE_PARM_DESC(mpt_msi_enable_spi, " Enable MSI Support for SPI \
86 controllers (default=0)");
87
88static int mpt_msi_enable_fc;
89module_param(mpt_msi_enable_fc, int, 0);
90MODULE_PARM_DESC(mpt_msi_enable_fc, " Enable MSI Support for FC \
91 controllers (default=0)");
92
93static int mpt_msi_enable_sas;
Yinghai Lu5ce78682009-02-18 11:25:32 -080094module_param(mpt_msi_enable_sas, int, 0);
Kashyap, Desaie3829682009-01-08 14:27:16 +053095MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS \
Yinghai Lu5ce78682009-02-18 11:25:32 -080096 controllers (default=0)");
Kashyap, Desaie3829682009-01-08 14:27:16 +053097
Christoph Hellwig4ddce142006-01-17 13:44:29 +000098
Eric Moore793955f2007-01-29 09:42:20 -070099static int mpt_channel_mapping;
100module_param(mpt_channel_mapping, int, 0);
101MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
102
Prakash, Sathya436ace72007-07-24 15:42:08 +0530103static int mpt_debug_level;
James Bottomleydb47c2d2007-07-28 13:40:21 -0400104static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
105module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
106 &mpt_debug_level, 0600);
Kashyap, Desaie3829682009-01-08 14:27:16 +0530107MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h \
108 - (default=0)");
109
Kashyap, Desai2f4c7822009-01-06 15:03:37 +0530110int mpt_fwfault_debug;
111EXPORT_SYMBOL(mpt_fwfault_debug);
112module_param_call(mpt_fwfault_debug, param_set_int, param_get_int,
113 &mpt_fwfault_debug, 0600);
114MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault"
115 " and halt Firmware on fault - (default=0)");
116
117
Prakash, Sathya436ace72007-07-24 15:42:08 +0530118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119#ifdef MFCNT
120static int mfcounter = 0;
121#define PRINT_MF_COUNT 20000
122#endif
123
124/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
125/*
126 * Public data...
127 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
Adrian Bunk15424922008-04-22 00:31:51 +0300129static struct proc_dir_entry *mpt_proc_root_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
131#define WHOINIT_UNKNOWN 0xAA
132
133/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
134/*
135 * Private data...
136 */
137 /* Adapter link list */
138LIST_HEAD(ioc_list);
139 /* Callback lookup table */
140static MPT_CALLBACK MptCallbacks[MPT_MAX_PROTOCOL_DRIVERS];
141 /* Protocol driver class lookup table */
142static int MptDriverClass[MPT_MAX_PROTOCOL_DRIVERS];
143 /* Event handler lookup table */
144static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
145 /* Reset handler lookup table */
146static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
147static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
148
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530150/*
151 * Driver Callback Index's
152 */
153static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
154static u8 last_drv_idx;
155
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
157/*
158 * Forward protos...
159 */
David Howells7d12e782006-10-05 14:55:46 +0100160static irqreturn_t mpt_interrupt(int irq, void *bus_id);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530161static int mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
162 MPT_FRAME_HDR *reply);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
164 u32 *req, int replyBytes, u16 *u16reply, int maxwait,
165 int sleepFlag);
166static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag);
167static void mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev);
168static void mpt_adapter_disable(MPT_ADAPTER *ioc);
169static void mpt_adapter_dispose(MPT_ADAPTER *ioc);
170
171static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc);
172static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason);
174static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
175static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag);
176static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag);
177static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200178static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
180static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag);
181static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag);
182static int PrimeIocFifos(MPT_ADAPTER *ioc);
183static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
184static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
185static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
186static int GetLanConfigPages(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187static int GetIoUnitPage2(MPT_ADAPTER *ioc);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200188int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
190static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
191static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
192static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +0530193static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
Kashyap, Desaifd761752009-05-29 16:39:06 +0530194static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch,
195 int sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200197static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
198static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
200#ifdef CONFIG_PROC_FS
201static int procmpt_summary_read(char *buf, char **start, off_t offset,
202 int request, int *eof, void *data);
203static int procmpt_version_read(char *buf, char **start, off_t offset,
204 int request, int *eof, void *data);
205static int procmpt_iocinfo_read(char *buf, char **start, off_t offset,
206 int request, int *eof, void *data);
207#endif
208static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
209
210//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
Kashyap, Desaifd761752009-05-29 16:39:06 +0530211static int ProcessEventNotification(MPT_ADAPTER *ioc,
212 EventNotificationReply_t *evReply, int *evHandlers);
Eric Moorec6c727a2007-01-29 09:44:54 -0700213static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric335a9412006-01-17 17:06:23 -0700215static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600216static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
Moore, Ericc972c702006-03-14 09:14:06 -0700217static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -0700218static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
220/* module entry point */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221static int __init fusion_init (void);
222static void __exit fusion_exit (void);
223
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224#define CHIPREG_READ32(addr) readl_relaxed(addr)
225#define CHIPREG_READ32_dmasync(addr) readl(addr)
226#define CHIPREG_WRITE32(addr,val) writel(val, addr)
227#define CHIPREG_PIO_WRITE32(addr,val) outl(val, (unsigned long)addr)
228#define CHIPREG_PIO_READ32(addr) inl((unsigned long)addr)
229
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -0600230static void
231pci_disable_io_access(struct pci_dev *pdev)
232{
233 u16 command_reg;
234
235 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
236 command_reg &= ~1;
237 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
238}
239
240static void
241pci_enable_io_access(struct pci_dev *pdev)
242{
243 u16 command_reg;
244
245 pci_read_config_word(pdev, PCI_COMMAND, &command_reg);
246 command_reg |= 1;
247 pci_write_config_word(pdev, PCI_COMMAND, command_reg);
248}
249
James Bottomleydb47c2d2007-07-28 13:40:21 -0400250static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
251{
252 int ret = param_set_int(val, kp);
253 MPT_ADAPTER *ioc;
254
255 if (ret)
256 return ret;
257
258 list_for_each_entry(ioc, &ioc_list, list)
259 ioc->debug_level = mpt_debug_level;
260 return 0;
261}
262
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530263/**
264 * mpt_get_cb_idx - obtain cb_idx for registered driver
265 * @dclass: class driver enum
266 *
267 * Returns cb_idx, or zero means it wasn't found
268 **/
269static u8
270mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
271{
272 u8 cb_idx;
273
274 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
275 if (MptDriverClass[cb_idx] == dclass)
276 return cb_idx;
277 return 0;
278}
279
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530280/**
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530281 * mpt_is_discovery_complete - determine if discovery has completed
282 * @ioc: per adatper instance
283 *
284 * Returns 1 when discovery completed, else zero.
285 */
286static int
287mpt_is_discovery_complete(MPT_ADAPTER *ioc)
288{
289 ConfigExtendedPageHeader_t hdr;
290 CONFIGPARMS cfg;
291 SasIOUnitPage0_t *buffer;
292 dma_addr_t dma_handle;
293 int rc = 0;
294
295 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
296 memset(&cfg, 0, sizeof(CONFIGPARMS));
297 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
298 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
299 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
300 cfg.cfghdr.ehdr = &hdr;
301 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
302
303 if ((mpt_config(ioc, &cfg)))
304 goto out;
305 if (!hdr.ExtPageLength)
306 goto out;
307
308 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
309 &dma_handle);
310 if (!buffer)
311 goto out;
312
313 cfg.physAddr = dma_handle;
314 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
315
316 if ((mpt_config(ioc, &cfg)))
317 goto out_free_consistent;
318
319 if (!(buffer->PhyData[0].PortFlags &
320 MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS))
321 rc = 1;
322
323 out_free_consistent:
324 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
325 buffer, dma_handle);
326 out:
327 return rc;
328}
329
330/**
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530331 * mpt_fault_reset_work - work performed on workq after ioc fault
332 * @work: input argument, used to derive ioc
333 *
334**/
335static void
336mpt_fault_reset_work(struct work_struct *work)
337{
338 MPT_ADAPTER *ioc =
339 container_of(work, MPT_ADAPTER, fault_reset_work.work);
340 u32 ioc_raw_state;
341 int rc;
342 unsigned long flags;
343
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +0530344 if (ioc->ioc_reset_in_progress || !ioc->active)
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530345 goto out;
346
347 ioc_raw_state = mpt_GetIocState(ioc, 0);
348 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
349 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700350 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530351 printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700352 ioc->name, __func__);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530353 rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
354 printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700355 __func__, (rc == 0) ? "success" : "failed");
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530356 ioc_raw_state = mpt_GetIocState(ioc, 0);
357 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
358 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
359 "reset (%04xh)\n", ioc->name, ioc_raw_state &
360 MPI_DOORBELL_DATA_MASK);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +0530361 } else if (ioc->bus_type == SAS && ioc->sas_discovery_quiesce_io) {
362 if ((mpt_is_discovery_complete(ioc))) {
363 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "clearing "
364 "discovery_quiesce_io flag\n", ioc->name));
365 ioc->sas_discovery_quiesce_io = 0;
366 }
Prakash, Sathyad54d48b2008-05-21 01:02:18 +0530367 }
368
369 out:
370 /*
371 * Take turns polling alternate controller
372 */
373 if (ioc->alt_ioc)
374 ioc = ioc->alt_ioc;
375
376 /* rearm the timer */
377 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
378 if (ioc->reset_work_q)
379 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
380 msecs_to_jiffies(MPT_POLLING_INTERVAL));
381 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
382}
383
384
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600385/*
386 * Process turbo (context) reply...
387 */
388static void
389mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
390{
391 MPT_FRAME_HDR *mf = NULL;
392 MPT_FRAME_HDR *mr = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530393 u16 req_idx = 0;
394 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600395
Prakash, Sathya436ace72007-07-24 15:42:08 +0530396 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600397 ioc->name, pa));
398
399 switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
400 case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT:
401 req_idx = pa & 0x0000FFFF;
402 cb_idx = (pa & 0x00FF0000) >> 16;
403 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
404 break;
405 case MPI_CONTEXT_REPLY_TYPE_LAN:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530406 cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600407 /*
408 * Blind set of mf to NULL here was fatal
409 * after lan_reply says "freeme"
410 * Fix sort of combined with an optimization here;
411 * added explicit check for case where lan_reply
412 * was just returning 1 and doing nothing else.
413 * For this case skip the callback, but set up
414 * proper mf value first here:-)
415 */
416 if ((pa & 0x58000000) == 0x58000000) {
417 req_idx = pa & 0x0000FFFF;
418 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
419 mpt_free_msg_frame(ioc, mf);
420 mb();
421 return;
422 break;
423 }
424 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
425 break;
426 case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530427 cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600428 mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
429 break;
430 default:
431 cb_idx = 0;
432 BUG();
433 }
434
435 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530436 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600437 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600438 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700439 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600440 goto out;
441 }
442
443 if (MptCallbacks[cb_idx](ioc, mf, mr))
444 mpt_free_msg_frame(ioc, mf);
445 out:
446 mb();
447}
448
449static void
450mpt_reply(MPT_ADAPTER *ioc, u32 pa)
451{
452 MPT_FRAME_HDR *mf;
453 MPT_FRAME_HDR *mr;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530454 u16 req_idx;
455 u8 cb_idx;
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600456 int freeme;
457
458 u32 reply_dma_low;
459 u16 ioc_stat;
460
461 /* non-TURBO reply! Hmmm, something may be up...
462 * Newest turbo reply mechanism; get address
463 * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)!
464 */
465
466 /* Map DMA address of reply header to cpu address.
467 * pa is 32 bits - but the dma address may be 32 or 64 bits
468 * get offset based only only the low addresses
469 */
470
471 reply_dma_low = (pa <<= 1);
472 mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames +
473 (reply_dma_low - ioc->reply_frames_low_dma));
474
475 req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx);
476 cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
477 mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
478
Prakash, Sathya436ace72007-07-24 15:42:08 +0530479 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600480 ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
Eric Moore29dd3602007-09-14 18:46:51 -0600481 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600482
483 /* Check/log IOC log info
484 */
485 ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus);
486 if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
487 u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
488 if (ioc->bus_type == FC)
489 mpt_fc_log_info(ioc, log_info);
Moore, Eric Deana9b29372005-11-16 18:54:20 -0700490 else if (ioc->bus_type == SPI)
Moore, Eric335a9412006-01-17 17:06:23 -0700491 mpt_spi_log_info(ioc, log_info);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600492 else if (ioc->bus_type == SAS)
493 mpt_sas_log_info(ioc, log_info);
494 }
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600495
Eric Moorec6c727a2007-01-29 09:44:54 -0700496 if (ioc_stat & MPI_IOCSTATUS_MASK)
497 mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600498
499 /* Check for (valid) IO callback! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530500 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
Eric Moore8d6d83e2007-09-14 18:47:40 -0600501 MptCallbacks[cb_idx] == NULL) {
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600502 printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700503 __func__, ioc->name, cb_idx);
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600504 freeme = 0;
505 goto out;
506 }
507
508 freeme = MptCallbacks[cb_idx](ioc, mf, mr);
509
510 out:
511 /* Flush (non-TURBO) reply with a WRITE! */
512 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa);
513
514 if (freeme)
515 mpt_free_msg_frame(ioc, mf);
516 mb();
517}
518
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800520/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 * mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
522 * @irq: irq number (not used)
523 * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 *
525 * This routine is registered via the request_irq() kernel API call,
526 * and handles all interrupts generated from a specific MPT adapter
527 * (also referred to as a IO Controller or IOC).
528 * This routine must clear the interrupt from the adapter and does
529 * so by reading the reply FIFO. Multiple replies may be processed
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200530 * per single call to this routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 *
532 * This routine handles register-level access of the adapter but
533 * dispatches (calls) a protocol-specific callback routine to handle
534 * the protocol-specific details of the MPT request completion.
535 */
536static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100537mpt_interrupt(int irq, void *bus_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538{
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600539 MPT_ADAPTER *ioc = bus_id;
Eric Moore3e00a5b2006-06-29 17:38:43 -0600540 u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
541
542 if (pa == 0xFFFFFFFF)
543 return IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
545 /*
546 * Drain the reply FIFO!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 */
Eric Moore3e00a5b2006-06-29 17:38:43 -0600548 do {
549 if (pa & MPI_ADDRESS_REPLY_A_BIT)
Moore, Eric Dean466544d2005-09-14 18:09:10 -0600550 mpt_reply(ioc, pa);
551 else
552 mpt_turbo_reply(ioc, pa);
Eric Moore3e00a5b2006-06-29 17:38:43 -0600553 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
554 } while (pa != 0xFFFFFFFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
556 return IRQ_HANDLED;
557}
558
559/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800560/**
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530561 * mptbase_reply - MPT base driver's callback routine
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 * @ioc: Pointer to MPT_ADAPTER structure
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530563 * @req: Pointer to original MPT request frame
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 * @reply: Pointer to MPT reply frame (NULL if TurboReply)
565 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800566 * MPT base driver's callback routine; all base driver
567 * "internal" request/reply processing is routed here.
568 * Currently used for EventNotification and EventAck handling.
569 *
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200570 * Returns 1 indicating original alloc'd request frame ptr
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 * should be freed, or 0 if it shouldn't.
572 */
573static int
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530574mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530576 EventNotificationReply_t *pEventReply;
577 u8 event;
578 int evHandlers;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 int freereq = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530581 switch (reply->u.hdr.Function) {
582 case MPI_FUNCTION_EVENT_NOTIFICATION:
583 pEventReply = (EventNotificationReply_t *)reply;
584 evHandlers = 0;
585 ProcessEventNotification(ioc, pEventReply, &evHandlers);
586 event = le32_to_cpu(pEventReply->Event) & 0xFF;
587 if (pEventReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 freereq = 0;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530589 if (event != MPI_EVENT_EVENT_CHANGE)
590 break;
591 case MPI_FUNCTION_CONFIG:
592 case MPI_FUNCTION_SAS_IO_UNIT_CONTROL:
593 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
594 if (reply) {
595 ioc->mptbase_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
596 memcpy(ioc->mptbase_cmds.reply, reply,
597 min(MPT_DEFAULT_FRAME_SIZE,
598 4 * reply->u.reply.MsgLength));
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200599 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +0530600 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
601 ioc->mptbase_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
602 complete(&ioc->mptbase_cmds.done);
603 } else
604 freereq = 0;
605 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_FREE_MF)
606 freereq = 1;
607 break;
608 case MPI_FUNCTION_EVENT_ACK:
609 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
610 "EventAck reply received\n", ioc->name));
611 break;
612 default:
613 printk(MYIOC_s_ERR_FMT
614 "Unexpected msg function (=%02Xh) reply received!\n",
615 ioc->name, reply->u.hdr.Function);
616 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
618
619 /*
620 * Conditionally tell caller to free the original
621 * EventNotification/EventAck/unexpected request frame!
622 */
623 return freereq;
624}
625
626/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
627/**
628 * mpt_register - Register protocol-specific main callback handler.
629 * @cbfunc: callback function pointer
630 * @dclass: Protocol driver's class (%MPT_DRIVER_CLASS enum value)
631 *
632 * This routine is called by a protocol-specific driver (SCSI host,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800633 * LAN, SCSI target) to register its reply callback routine. Each
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 * protocol-specific driver must do this before it will be able to
635 * use any IOC resources, such as obtaining request frames.
636 *
637 * NOTES: The SCSI protocol driver currently calls this routine thrice
638 * in order to register separate callbacks; one for "normal" SCSI IO;
639 * one for MptScsiTaskMgmt requests; one for Scan/DV requests.
640 *
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530641 * Returns u8 valued "handle" in the range (and S.O.D. order)
642 * {N,...,7,6,5,...,1} if successful.
643 * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
644 * considered an error by the caller.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530646u8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
648{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530649 u8 cb_idx;
650 last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
652 /*
653 * Search for empty callback slot in this order: {N,...,7,6,5,...,1}
654 * (slot/handle 0 is reserved!)
655 */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530656 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
657 if (MptCallbacks[cb_idx] == NULL) {
658 MptCallbacks[cb_idx] = cbfunc;
659 MptDriverClass[cb_idx] = dclass;
660 MptEvHandlers[cb_idx] = NULL;
661 last_drv_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 break;
663 }
664 }
665
666 return last_drv_idx;
667}
668
669/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
670/**
671 * mpt_deregister - Deregister a protocol drivers resources.
672 * @cb_idx: previously registered callback handle
673 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800674 * Each protocol-specific driver should call this routine when its
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 * module is unloaded.
676 */
677void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530678mpt_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600680 if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 MptCallbacks[cb_idx] = NULL;
682 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
683 MptEvHandlers[cb_idx] = NULL;
684
685 last_drv_idx++;
686 }
687}
688
689/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
690/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800691 * mpt_event_register - Register protocol-specific event callback handler.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 * @cb_idx: previously registered (via mpt_register) callback handle
693 * @ev_cbfunc: callback function
694 *
695 * This routine can be called by one or more protocol-specific drivers
696 * if/when they choose to be notified of MPT events.
697 *
698 * Returns 0 for success.
699 */
700int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530701mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600703 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 return -1;
705
706 MptEvHandlers[cb_idx] = ev_cbfunc;
707 return 0;
708}
709
710/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
711/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800712 * mpt_event_deregister - Deregister protocol-specific event callback handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 * @cb_idx: previously registered callback handle
714 *
715 * Each protocol-specific driver should call this routine
716 * when it does not (or can no longer) handle events,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800717 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 */
719void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530720mpt_event_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721{
Eric Moore8d6d83e2007-09-14 18:47:40 -0600722 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 return;
724
725 MptEvHandlers[cb_idx] = NULL;
726}
727
728/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
729/**
730 * mpt_reset_register - Register protocol-specific IOC reset handler.
731 * @cb_idx: previously registered (via mpt_register) callback handle
732 * @reset_func: reset function
733 *
734 * This routine can be called by one or more protocol-specific drivers
735 * if/when they choose to be notified of IOC resets.
736 *
737 * Returns 0 for success.
738 */
739int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530740mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530742 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 return -1;
744
745 MptResetHandlers[cb_idx] = reset_func;
746 return 0;
747}
748
749/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
750/**
751 * mpt_reset_deregister - Deregister protocol-specific IOC reset handler.
752 * @cb_idx: previously registered callback handle
753 *
754 * Each protocol-specific driver should call this routine
755 * when it does not (or can no longer) handle IOC reset handling,
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800756 * or when its module is unloaded.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 */
758void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530759mpt_reset_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760{
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530761 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return;
763
764 MptResetHandlers[cb_idx] = NULL;
765}
766
767/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
768/**
769 * mpt_device_driver_register - Register device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800770 * @dd_cbfunc: driver callbacks struct
771 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 */
773int
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530774mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
776 MPT_ADAPTER *ioc;
Eric Moored58b2722006-07-11 17:23:23 -0600777 const struct pci_device_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Eric Moore8d6d83e2007-09-14 18:47:40 -0600779 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400780 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
782 MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
783
784 /* call per pci device probe entry point */
785 list_for_each_entry(ioc, &ioc_list, list) {
Eric Moored58b2722006-07-11 17:23:23 -0600786 id = ioc->pcidev->driver ?
787 ioc->pcidev->driver->id_table : NULL;
788 if (dd_cbfunc->probe)
789 dd_cbfunc->probe(ioc->pcidev, id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 }
791
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -0400792 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793}
794
795/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
796/**
797 * mpt_device_driver_deregister - DeRegister device driver hooks
Randy Dunlapd9489fb2006-12-06 20:38:43 -0800798 * @cb_idx: MPT protocol driver index
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 */
800void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530801mpt_device_driver_deregister(u8 cb_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802{
803 struct mpt_pci_driver *dd_cbfunc;
804 MPT_ADAPTER *ioc;
805
Eric Moore8d6d83e2007-09-14 18:47:40 -0600806 if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 return;
808
809 dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
810
811 list_for_each_entry(ioc, &ioc_list, list) {
812 if (dd_cbfunc->remove)
813 dd_cbfunc->remove(ioc->pcidev);
814 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200815
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 MptDeviceDriverHandlers[cb_idx] = NULL;
817}
818
819
820/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
821/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800822 * mpt_get_msg_frame - Obtain an MPT request frame from the pool
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530823 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 * @ioc: Pointer to MPT adapter structure
825 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800826 * Obtain an MPT request frame from the pool (of 1024) that are
827 * allocated per MPT adapter.
828 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 * Returns pointer to a MPT request frame or %NULL if none are available
830 * or IOC is not active.
831 */
832MPT_FRAME_HDR*
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530833mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834{
835 MPT_FRAME_HDR *mf;
836 unsigned long flags;
837 u16 req_idx; /* Request index */
838
839 /* validate handle and ioc identifier */
840
841#ifdef MFCNT
842 if (!ioc->active)
Eric Moore29dd3602007-09-14 18:46:51 -0600843 printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
844 "returning NULL!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845#endif
846
847 /* If interrupts are not attached, do not return a request frame */
848 if (!ioc->active)
849 return NULL;
850
851 spin_lock_irqsave(&ioc->FreeQlock, flags);
852 if (!list_empty(&ioc->FreeQ)) {
853 int req_offset;
854
855 mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR,
856 u.frame.linkage.list);
857 list_del(&mf->u.frame.linkage.list);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200858 mf->u.frame.linkage.arg1 = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530859 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
861 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500862 req_idx = req_offset / ioc->req_sz;
863 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
Eric Moore29dd3602007-09-14 18:46:51 -0600865 /* Default, will be changed if necessary in SG generation */
866 ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867#ifdef MFCNT
868 ioc->mfcnt++;
869#endif
870 }
871 else
872 mf = NULL;
873 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
874
875#ifdef MFCNT
876 if (mf == NULL)
Eric Moore29dd3602007-09-14 18:46:51 -0600877 printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
878 "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
879 ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 mfcounter++;
881 if (mfcounter == PRINT_MF_COUNT)
Eric Moore29dd3602007-09-14 18:46:51 -0600882 printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
883 ioc->mfcnt, ioc->req_depth);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884#endif
885
Eric Moore29dd3602007-09-14 18:46:51 -0600886 dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
887 ioc->name, cb_idx, ioc->id, mf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 return mf;
889}
890
891/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
892/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800893 * mpt_put_msg_frame - Send a protocol-specific MPT request frame to an IOC
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530894 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 * @ioc: Pointer to MPT adapter structure
896 * @mf: Pointer to MPT request frame
897 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800898 * This routine posts an MPT request frame to the request post FIFO of a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 * specific MPT adapter.
900 */
901void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530902mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903{
904 u32 mf_dma_addr;
905 int req_offset;
906 u16 req_idx; /* Request index */
907
908 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530909 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
911 /* u16! */
Moore, Eric Dean d335cc32005-04-30 17:09:38 -0500912 req_idx = req_offset / ioc->req_sz;
913 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
915
Prakash, Sathya436ace72007-07-24 15:42:08 +0530916 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
Christoph Hellwigc6678e02005-08-18 16:24:53 +0200918 mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
Eric Moore29dd3602007-09-14 18:46:51 -0600919 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
920 "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
921 ioc->RequestNB[req_idx]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
923}
924
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530925/**
Randy Dunlap7105a382008-02-29 22:03:27 -0800926 * mpt_put_msg_frame_hi_pri - Send a hi-pri protocol-specific MPT request frame
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530927 * @cb_idx: Handle of registered MPT protocol driver
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530928 * @ioc: Pointer to MPT adapter structure
929 * @mf: Pointer to MPT request frame
930 *
Randy Dunlap7105a382008-02-29 22:03:27 -0800931 * Send a protocol-specific MPT request frame to an IOC using
932 * hi-priority request queue.
933 *
934 * This routine posts an MPT request frame to the request post FIFO of a
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530935 * specific MPT adapter.
936 **/
937void
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530938mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530939{
940 u32 mf_dma_addr;
941 int req_offset;
942 u16 req_idx; /* Request index */
943
944 /* ensure values are reset properly! */
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530945 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530946 req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
947 req_idx = req_offset / ioc->req_sz;
948 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
949 mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
950
951 DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
952
953 mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
954 dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
955 ioc->name, mf_dma_addr, req_idx));
956 CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
957}
958
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
960/**
961 * mpt_free_msg_frame - Place MPT request frame back on FreeQ.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 * @ioc: Pointer to MPT adapter structure
963 * @mf: Pointer to MPT request frame
964 *
965 * This routine places a MPT request frame back on the MPT adapter's
966 * FreeQ.
967 */
968void
969mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
970{
971 unsigned long flags;
972
973 /* Put Request back on FreeQ! */
974 spin_lock_irqsave(&ioc->FreeQlock, flags);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +0200975 mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
977#ifdef MFCNT
978 ioc->mfcnt--;
979#endif
980 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
981}
982
983/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
984/**
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530985 * mpt_add_sge - Place a simple 32 bit SGE at address pAddr.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 * @pAddr: virtual address for SGE
987 * @flagslength: SGE flags and data transfer length
988 * @dma_addr: Physical address
989 *
990 * This routine places a MPT request frame back on the MPT adapter's
991 * FreeQ.
992 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530993static void
994mpt_add_sge(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995{
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +0530996 SGESimple32_t *pSge = (SGESimple32_t *) pAddr;
997 pSge->FlagsLength = cpu_to_le32(flagslength);
998 pSge->Address = cpu_to_le32(dma_addr);
999}
1000
1001/**
1002 * mpt_add_sge_64bit - Place a simple 64 bit SGE at address pAddr.
1003 * @pAddr: virtual address for SGE
1004 * @flagslength: SGE flags and data transfer length
1005 * @dma_addr: Physical address
1006 *
1007 * This routine places a MPT request frame back on the MPT adapter's
1008 * FreeQ.
1009 **/
1010static void
1011mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1012{
1013 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1014 pSge->Address.Low = cpu_to_le32
1015 (lower_32_bits((unsigned long)(dma_addr)));
1016 pSge->Address.High = cpu_to_le32
1017 (upper_32_bits((unsigned long)dma_addr));
1018 pSge->FlagsLength = cpu_to_le32
1019 ((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1020}
1021
1022/**
1023 * mpt_add_sge_64bit_1078 - Place a simple 64 bit SGE at address pAddr
1024 * (1078 workaround).
1025 * @pAddr: virtual address for SGE
1026 * @flagslength: SGE flags and data transfer length
1027 * @dma_addr: Physical address
1028 *
1029 * This routine places a MPT request frame back on the MPT adapter's
1030 * FreeQ.
1031 **/
1032static void
1033mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
1034{
1035 SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
1036 u32 tmp;
1037
1038 pSge->Address.Low = cpu_to_le32
1039 (lower_32_bits((unsigned long)(dma_addr)));
1040 tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
1041
1042 /*
1043 * 1078 errata workaround for the 36GB limitation
1044 */
1045 if ((((u64)dma_addr + MPI_SGE_LENGTH(flagslength)) >> 32) == 9) {
1046 flagslength |=
1047 MPI_SGE_SET_FLAGS(MPI_SGE_FLAGS_LOCAL_ADDRESS);
1048 tmp |= (1<<31);
1049 if (mpt_debug_level & MPT_DEBUG_36GB_MEM)
1050 printk(KERN_DEBUG "1078 P0M2 addressing for "
1051 "addr = 0x%llx len = %d\n",
1052 (unsigned long long)dma_addr,
1053 MPI_SGE_LENGTH(flagslength));
1054 }
1055
1056 pSge->Address.High = cpu_to_le32(tmp);
1057 pSge->FlagsLength = cpu_to_le32(
1058 (flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
1059}
1060
1061/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1062/**
1063 * mpt_add_chain - Place a 32 bit chain SGE at address pAddr.
1064 * @pAddr: virtual address for SGE
1065 * @next: nextChainOffset value (u32's)
1066 * @length: length of next SGL segment
1067 * @dma_addr: Physical address
1068 *
1069 */
1070static void
1071mpt_add_chain(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1072{
1073 SGEChain32_t *pChain = (SGEChain32_t *) pAddr;
1074 pChain->Length = cpu_to_le16(length);
1075 pChain->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
1076 pChain->NextChainOffset = next;
1077 pChain->Address = cpu_to_le32(dma_addr);
1078}
1079
1080/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1081/**
1082 * mpt_add_chain_64bit - Place a 64 bit chain SGE at address pAddr.
1083 * @pAddr: virtual address for SGE
1084 * @next: nextChainOffset value (u32's)
1085 * @length: length of next SGL segment
1086 * @dma_addr: Physical address
1087 *
1088 */
1089static void
1090mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
1091{
1092 SGEChain64_t *pChain = (SGEChain64_t *) pAddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 u32 tmp = dma_addr & 0xFFFFFFFF;
1094
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301095 pChain->Length = cpu_to_le16(length);
1096 pChain->Flags = (MPI_SGE_FLAGS_CHAIN_ELEMENT |
1097 MPI_SGE_FLAGS_64_BIT_ADDRESSING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301099 pChain->NextChainOffset = next;
1100
1101 pChain->Address.Low = cpu_to_le32(tmp);
1102 tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
1103 pChain->Address.High = cpu_to_le32(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104}
1105
1106/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1107/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001108 * mpt_send_handshake_request - Send MPT request via doorbell handshake method.
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301109 * @cb_idx: Handle of registered MPT protocol driver
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 * @ioc: Pointer to MPT adapter structure
1111 * @reqBytes: Size of the request in bytes
1112 * @req: Pointer to MPT request frame
1113 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
1114 *
1115 * This routine is used exclusively to send MptScsiTaskMgmt
1116 * requests since they are required to be sent via doorbell handshake.
1117 *
1118 * NOTE: It is the callers responsibility to byte-swap fields in the
1119 * request which are greater than 1 byte in size.
1120 *
1121 * Returns 0 for success, non-zero for failure.
1122 */
1123int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301124mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125{
Eric Moorecd2c6192007-01-29 09:47:47 -07001126 int r = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 u8 *req_as_bytes;
1128 int ii;
1129
1130 /* State is known to be good upon entering
1131 * this function so issue the bus reset
1132 * request.
1133 */
1134
1135 /*
1136 * Emulate what mpt_put_msg_frame() does /wrt to sanity
1137 * setting cb_idx/req_idx. But ONLY if this request
1138 * is in proper (pre-alloc'd) request buffer range...
1139 */
1140 ii = MFPTR_2_MPT_INDEX(ioc,(MPT_FRAME_HDR*)req);
1141 if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
1142 MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
1143 mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301144 mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 }
1146
1147 /* Make sure there are no doorbells */
1148 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001149
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1151 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
1152 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
1153
1154 /* Wait for IOC doorbell int */
1155 if ((ii = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) {
1156 return ii;
1157 }
1158
1159 /* Read doorbell and check for active bit */
1160 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
1161 return -5;
1162
Eric Moore29dd3602007-09-14 18:46:51 -06001163 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001164 ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
1166 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1167
1168 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1169 return -2;
1170 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001171
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 /* Send request via doorbell handshake */
1173 req_as_bytes = (u8 *) req;
1174 for (ii = 0; ii < reqBytes/4; ii++) {
1175 u32 word;
1176
1177 word = ((req_as_bytes[(ii*4) + 0] << 0) |
1178 (req_as_bytes[(ii*4) + 1] << 8) |
1179 (req_as_bytes[(ii*4) + 2] << 16) |
1180 (req_as_bytes[(ii*4) + 3] << 24));
1181 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
1182 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1183 r = -3;
1184 break;
1185 }
1186 }
1187
1188 if (r >= 0 && WaitForDoorbellInt(ioc, 10, sleepFlag) >= 0)
1189 r = 0;
1190 else
1191 r = -4;
1192
1193 /* Make sure there are no doorbells */
1194 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001195
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 return r;
1197}
1198
1199/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1200/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001201 * mpt_host_page_access_control - control the IOC's Host Page Buffer access
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001202 * @ioc: Pointer to MPT adapter structure
1203 * @access_control_value: define bits below
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001204 * @sleepFlag: Specifies whether the process can sleep
1205 *
1206 * Provides mechanism for the host driver to control the IOC's
1207 * Host Page Buffer access.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001208 *
1209 * Access Control Value - bits[15:12]
1210 * 0h Reserved
1211 * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS }
1212 * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS }
1213 * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER }
1214 *
1215 * Returns 0 for success, non-zero for failure.
1216 */
1217
1218static int
1219mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag)
1220{
1221 int r = 0;
1222
1223 /* return if in use */
1224 if (CHIPREG_READ32(&ioc->chip->Doorbell)
1225 & MPI_DOORBELL_ACTIVE)
1226 return -1;
1227
1228 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1229
1230 CHIPREG_WRITE32(&ioc->chip->Doorbell,
1231 ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL
1232 <<MPI_DOORBELL_FUNCTION_SHIFT) |
1233 (access_control_value<<12)));
1234
1235 /* Wait for IOC to clear Doorbell Status bit */
1236 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) {
1237 return -2;
1238 }else
1239 return 0;
1240}
1241
1242/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1243/**
1244 * mpt_host_page_alloc - allocate system memory for the fw
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001245 * @ioc: Pointer to pointer to IOC adapter
1246 * @ioc_init: Pointer to ioc init config page
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001247 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001248 * If we already allocated memory in past, then resend the same pointer.
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001249 * Returns 0 for success, non-zero for failure.
1250 */
1251static int
1252mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
1253{
1254 char *psge;
1255 int flags_length;
1256 u32 host_page_buffer_sz=0;
1257
1258 if(!ioc->HostPageBuffer) {
1259
1260 host_page_buffer_sz =
1261 le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF;
1262
1263 if(!host_page_buffer_sz)
1264 return 0; /* fw doesn't need any host buffers */
1265
1266 /* spin till we get enough memory */
1267 while(host_page_buffer_sz > 0) {
1268
1269 if((ioc->HostPageBuffer = pci_alloc_consistent(
1270 ioc->pcidev,
1271 host_page_buffer_sz,
1272 &ioc->HostPageBuffer_dma)) != NULL) {
1273
Prakash, Sathya436ace72007-07-24 15:42:08 +05301274 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001275 "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
Eric Mooreba856d32006-07-11 17:34:01 -06001276 ioc->name, ioc->HostPageBuffer,
1277 (u32)ioc->HostPageBuffer_dma,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001278 host_page_buffer_sz));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001279 ioc->alloc_total += host_page_buffer_sz;
1280 ioc->HostPageBuffer_sz = host_page_buffer_sz;
1281 break;
1282 }
1283
1284 host_page_buffer_sz -= (4*1024);
1285 }
1286 }
1287
1288 if(!ioc->HostPageBuffer) {
1289 printk(MYIOC_s_ERR_FMT
1290 "Failed to alloc memory for host_page_buffer!\n",
1291 ioc->name);
1292 return -999;
1293 }
1294
1295 psge = (char *)&ioc_init->HostPageBufferSGE;
1296 flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1297 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
1298 MPI_SGE_FLAGS_32_BIT_ADDRESSING |
1299 MPI_SGE_FLAGS_HOST_TO_IOC |
1300 MPI_SGE_FLAGS_END_OF_BUFFER;
1301 if (sizeof(dma_addr_t) == sizeof(u64)) {
1302 flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING;
1303 }
1304 flags_length = flags_length << MPI_SGE_FLAGS_SHIFT;
1305 flags_length |= ioc->HostPageBuffer_sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301306 ioc->add_sge(psge, flags_length, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001307 ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE;
1308
1309return 0;
1310}
1311
1312/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
1313/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001314 * mpt_verify_adapter - Given IOC identifier, set pointer to its adapter structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 * @iocid: IOC unique identifier (integer)
1316 * @iocpp: Pointer to pointer to IOC adapter
1317 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001318 * Given a unique IOC identifier, set pointer to the associated MPT
1319 * adapter structure.
1320 *
1321 * Returns iocid and sets iocpp if iocid is found.
1322 * Returns -1 if iocid is not found.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 */
1324int
1325mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
1326{
1327 MPT_ADAPTER *ioc;
1328
1329 list_for_each_entry(ioc,&ioc_list,list) {
1330 if (ioc->id == iocid) {
1331 *iocpp =ioc;
1332 return iocid;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001335
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 *iocpp = NULL;
1337 return -1;
1338}
1339
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301340/**
1341 * mpt_get_product_name - returns product string
1342 * @vendor: pci vendor id
1343 * @device: pci device id
1344 * @revision: pci revision id
1345 * @prod_name: string returned
1346 *
1347 * Returns product string displayed when driver loads,
1348 * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
1349 *
1350 **/
1351static void
1352mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
1353{
1354 char *product_str = NULL;
1355
1356 if (vendor == PCI_VENDOR_ID_BROCADE) {
1357 switch (device)
1358 {
1359 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1360 switch (revision)
1361 {
1362 case 0x00:
1363 product_str = "BRE040 A0";
1364 break;
1365 case 0x01:
1366 product_str = "BRE040 A1";
1367 break;
1368 default:
1369 product_str = "BRE040";
1370 break;
1371 }
1372 break;
1373 }
1374 goto out;
1375 }
1376
1377 switch (device)
1378 {
1379 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1380 product_str = "LSIFC909 B1";
1381 break;
1382 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1383 product_str = "LSIFC919 B0";
1384 break;
1385 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1386 product_str = "LSIFC929 B0";
1387 break;
1388 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
1389 if (revision < 0x80)
1390 product_str = "LSIFC919X A0";
1391 else
1392 product_str = "LSIFC919XL A1";
1393 break;
1394 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
1395 if (revision < 0x80)
1396 product_str = "LSIFC929X A0";
1397 else
1398 product_str = "LSIFC929XL A1";
1399 break;
1400 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1401 product_str = "LSIFC939X A1";
1402 break;
1403 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1404 product_str = "LSIFC949X A1";
1405 break;
1406 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
1407 switch (revision)
1408 {
1409 case 0x00:
1410 product_str = "LSIFC949E A0";
1411 break;
1412 case 0x01:
1413 product_str = "LSIFC949E A1";
1414 break;
1415 default:
1416 product_str = "LSIFC949E";
1417 break;
1418 }
1419 break;
1420 case MPI_MANUFACTPAGE_DEVID_53C1030:
1421 switch (revision)
1422 {
1423 case 0x00:
1424 product_str = "LSI53C1030 A0";
1425 break;
1426 case 0x01:
1427 product_str = "LSI53C1030 B0";
1428 break;
1429 case 0x03:
1430 product_str = "LSI53C1030 B1";
1431 break;
1432 case 0x07:
1433 product_str = "LSI53C1030 B2";
1434 break;
1435 case 0x08:
1436 product_str = "LSI53C1030 C0";
1437 break;
1438 case 0x80:
1439 product_str = "LSI53C1030T A0";
1440 break;
1441 case 0x83:
1442 product_str = "LSI53C1030T A2";
1443 break;
1444 case 0x87:
1445 product_str = "LSI53C1030T A3";
1446 break;
1447 case 0xc1:
1448 product_str = "LSI53C1020A A1";
1449 break;
1450 default:
1451 product_str = "LSI53C1030";
1452 break;
1453 }
1454 break;
1455 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
1456 switch (revision)
1457 {
1458 case 0x03:
1459 product_str = "LSI53C1035 A2";
1460 break;
1461 case 0x04:
1462 product_str = "LSI53C1035 B0";
1463 break;
1464 default:
1465 product_str = "LSI53C1035";
1466 break;
1467 }
1468 break;
1469 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1470 switch (revision)
1471 {
1472 case 0x00:
1473 product_str = "LSISAS1064 A1";
1474 break;
1475 case 0x01:
1476 product_str = "LSISAS1064 A2";
1477 break;
1478 case 0x02:
1479 product_str = "LSISAS1064 A3";
1480 break;
1481 case 0x03:
1482 product_str = "LSISAS1064 A4";
1483 break;
1484 default:
1485 product_str = "LSISAS1064";
1486 break;
1487 }
1488 break;
1489 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1490 switch (revision)
1491 {
1492 case 0x00:
1493 product_str = "LSISAS1064E A0";
1494 break;
1495 case 0x01:
1496 product_str = "LSISAS1064E B0";
1497 break;
1498 case 0x02:
1499 product_str = "LSISAS1064E B1";
1500 break;
1501 case 0x04:
1502 product_str = "LSISAS1064E B2";
1503 break;
1504 case 0x08:
1505 product_str = "LSISAS1064E B3";
1506 break;
1507 default:
1508 product_str = "LSISAS1064E";
1509 break;
1510 }
1511 break;
1512 case MPI_MANUFACTPAGE_DEVID_SAS1068:
1513 switch (revision)
1514 {
1515 case 0x00:
1516 product_str = "LSISAS1068 A0";
1517 break;
1518 case 0x01:
1519 product_str = "LSISAS1068 B0";
1520 break;
1521 case 0x02:
1522 product_str = "LSISAS1068 B1";
1523 break;
1524 default:
1525 product_str = "LSISAS1068";
1526 break;
1527 }
1528 break;
1529 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1530 switch (revision)
1531 {
1532 case 0x00:
1533 product_str = "LSISAS1068E A0";
1534 break;
1535 case 0x01:
1536 product_str = "LSISAS1068E B0";
1537 break;
1538 case 0x02:
1539 product_str = "LSISAS1068E B1";
1540 break;
1541 case 0x04:
1542 product_str = "LSISAS1068E B2";
1543 break;
1544 case 0x08:
1545 product_str = "LSISAS1068E B3";
1546 break;
1547 default:
1548 product_str = "LSISAS1068E";
1549 break;
1550 }
1551 break;
1552 case MPI_MANUFACTPAGE_DEVID_SAS1078:
1553 switch (revision)
1554 {
1555 case 0x00:
1556 product_str = "LSISAS1078 A0";
1557 break;
1558 case 0x01:
1559 product_str = "LSISAS1078 B0";
1560 break;
1561 case 0x02:
1562 product_str = "LSISAS1078 C0";
1563 break;
1564 case 0x03:
1565 product_str = "LSISAS1078 C1";
1566 break;
1567 case 0x04:
1568 product_str = "LSISAS1078 C2";
1569 break;
1570 default:
1571 product_str = "LSISAS1078";
1572 break;
1573 }
1574 break;
1575 }
1576
1577 out:
1578 if (product_str)
1579 sprintf(prod_name, "%s", product_str);
1580}
1581
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301582/**
1583 * mpt_mapresources - map in memory mapped io
1584 * @ioc: Pointer to pointer to IOC adapter
1585 *
1586 **/
1587static int
1588mpt_mapresources(MPT_ADAPTER *ioc)
1589{
1590 u8 __iomem *mem;
1591 int ii;
1592 unsigned long mem_phys;
1593 unsigned long port;
1594 u32 msize;
1595 u32 psize;
1596 u8 revision;
1597 int r = -ENODEV;
1598 struct pci_dev *pdev;
1599
1600 pdev = ioc->pcidev;
1601 ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
1602 if (pci_enable_device_mem(pdev)) {
1603 printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() "
1604 "failed\n", ioc->name);
1605 return r;
1606 }
1607 if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) {
1608 printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with "
1609 "MEM failed\n", ioc->name);
1610 return r;
1611 }
1612
1613 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1614
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301615 if (sizeof(dma_addr_t) > 4) {
1616 const uint64_t required_mask = dma_get_required_mask
1617 (&pdev->dev);
1618 if (required_mask > DMA_BIT_MASK(32)
1619 && !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))
1620 && !pci_set_consistent_dma_mask(pdev,
1621 DMA_BIT_MASK(64))) {
1622 ioc->dma_mask = DMA_BIT_MASK(64);
1623 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1624 ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1625 ioc->name));
1626 } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1627 && !pci_set_consistent_dma_mask(pdev,
1628 DMA_BIT_MASK(32))) {
1629 ioc->dma_mask = DMA_BIT_MASK(32);
1630 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1631 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1632 ioc->name));
1633 } else {
1634 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1635 ioc->name, pci_name(pdev));
1636 return r;
1637 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301638 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301639 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
1640 && !pci_set_consistent_dma_mask(pdev,
1641 DMA_BIT_MASK(32))) {
1642 ioc->dma_mask = DMA_BIT_MASK(32);
1643 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
1644 ": 32 BIT PCI BUS DMA ADDRESSING SUPPORTED\n",
1645 ioc->name));
1646 } else {
1647 printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n",
1648 ioc->name, pci_name(pdev));
1649 return r;
1650 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301651 }
1652
1653 mem_phys = msize = 0;
1654 port = psize = 0;
1655 for (ii = 0; ii < DEVICE_COUNT_RESOURCE; ii++) {
1656 if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
1657 if (psize)
1658 continue;
1659 /* Get I/O space! */
1660 port = pci_resource_start(pdev, ii);
1661 psize = pci_resource_len(pdev, ii);
1662 } else {
1663 if (msize)
1664 continue;
1665 /* Get memmap */
1666 mem_phys = pci_resource_start(pdev, ii);
1667 msize = pci_resource_len(pdev, ii);
1668 }
1669 }
1670 ioc->mem_size = msize;
1671
1672 mem = NULL;
1673 /* Get logical ptr for PciMem0 space */
1674 /*mem = ioremap(mem_phys, msize);*/
1675 mem = ioremap(mem_phys, msize);
1676 if (mem == NULL) {
1677 printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter"
1678 " memory!\n", ioc->name);
1679 return -EINVAL;
1680 }
1681 ioc->memmap = mem;
1682 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n",
1683 ioc->name, mem, mem_phys));
1684
1685 ioc->mem_phys = mem_phys;
1686 ioc->chip = (SYSIF_REGS __iomem *)mem;
1687
1688 /* Save Port IO values in case we need to do downloadboot */
1689 ioc->pio_mem_phys = port;
1690 ioc->pio_chip = (SYSIF_REGS __iomem *)port;
1691
1692 return 0;
1693}
1694
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001696/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001697 * mpt_attach - Install a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 * @pdev: Pointer to pci_dev structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001699 * @id: PCI device ID information
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 *
1701 * This routine performs all the steps necessary to bring the IOC of
1702 * a MPT adapter to a OPERATIONAL state. This includes registering
1703 * memory regions, registering the interrupt, and allocating request
1704 * and reply memory pools.
1705 *
1706 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
1707 * MPT adapter.
1708 *
1709 * Returns 0 for success, non-zero for failure.
1710 *
1711 * TODO: Add support for polled controllers
1712 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001713int
1714mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715{
1716 MPT_ADAPTER *ioc;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301717 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 int r = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 u8 revision;
1720 u8 pcixcmd;
1721 static int mpt_ids = 0;
1722#ifdef CONFIG_PROC_FS
1723 struct proc_dir_entry *dent, *ent;
1724#endif
1725
Jesper Juhl56876192007-08-10 14:50:51 -07001726 ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
1727 if (ioc == NULL) {
1728 printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
1729 return -ENOMEM;
1730 }
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301731
Eric Moore29dd3602007-09-14 18:46:51 -06001732 ioc->id = mpt_ids++;
1733 sprintf(ioc->name, "ioc%d", ioc->id);
Jesper Juhl56876192007-08-10 14:50:51 -07001734
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301735 /*
1736 * set initial debug level
1737 * (refer to mptdebug.h)
1738 *
1739 */
1740 ioc->debug_level = mpt_debug_level;
1741 if (mpt_debug_level)
1742 printk(KERN_INFO "mpt_debug_level=%xh\n", mpt_debug_level);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05301743
Eric Moore29dd3602007-09-14 18:46:51 -06001744 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001745
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301746 ioc->pcidev = pdev;
1747 if (mpt_mapresources(ioc)) {
Jesper Juhl56876192007-08-10 14:50:51 -07001748 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 return r;
1750 }
1751
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301752 /*
1753 * Setting up proper handlers for scatter gather handling
1754 */
1755 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
1756 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
1757 ioc->add_sge = &mpt_add_sge_64bit_1078;
1758 else
1759 ioc->add_sge = &mpt_add_sge_64bit;
1760 ioc->add_chain = &mpt_add_chain_64bit;
1761 ioc->sg_addr_size = 8;
1762 } else {
1763 ioc->add_sge = &mpt_add_sge;
1764 ioc->add_chain = &mpt_add_chain;
1765 ioc->sg_addr_size = 4;
1766 }
1767 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
1768
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 ioc->alloc_total = sizeof(MPT_ADAPTER);
1770 ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
1771 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001772
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 ioc->pcidev = pdev;
Moore, Eric Dean2a238ea2005-12-01 10:50:32 -07001774 spin_lock_init(&ioc->initializing_hba_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301776 spin_lock_init(&ioc->taskmgmt_lock);
Kashyap, Desai37c60f32009-05-29 16:44:06 +05301777 mutex_init(&ioc->internal_cmds.mutex);
1778 init_completion(&ioc->internal_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301779 mutex_init(&ioc->mptbase_cmds.mutex);
1780 init_completion(&ioc->mptbase_cmds.done);
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05301781 mutex_init(&ioc->taskmgmt_cmds.mutex);
1782 init_completion(&ioc->taskmgmt_cmds.done);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301783
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 /* Initialize the event logging.
1785 */
1786 ioc->eventTypes = 0; /* None */
1787 ioc->eventContext = 0;
1788 ioc->eventLogSize = 0;
1789 ioc->events = NULL;
1790
1791#ifdef MFCNT
1792 ioc->mfcnt = 0;
1793#endif
1794
1795 ioc->cached_fw = NULL;
1796
1797 /* Initilize SCSI Config Data structure
1798 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06001799 memset(&ioc->spi_data, 0, sizeof(SpiCfgData));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800
Michael Reed05e8ec12006-01-13 14:31:54 -06001801 /* Initialize the fc rport list head.
1802 */
1803 INIT_LIST_HEAD(&ioc->fc_rports);
1804
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 /* Find lookup slot. */
1806 INIT_LIST_HEAD(&ioc->list);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02001807
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301808
1809 /* Initialize workqueue */
1810 INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
1811 spin_lock_init(&ioc->fault_reset_work_lock);
1812
Kay Sieversaab0de22008-05-02 06:02:41 +02001813 snprintf(ioc->reset_work_q_name, sizeof(ioc->reset_work_q_name),
1814 "mpt_poll_%d", ioc->id);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301815 ioc->reset_work_q =
1816 create_singlethread_workqueue(ioc->reset_work_q_name);
1817 if (!ioc->reset_work_q) {
1818 printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
1819 ioc->name);
1820 pci_release_selected_regions(pdev, ioc->bars);
1821 kfree(ioc);
1822 return -ENOMEM;
1823 }
1824
Eric Moore29dd3602007-09-14 18:46:51 -06001825 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
1826 ioc->name, &ioc->facts, &ioc->pfacts[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301828 pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
1829 mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
1830
1831 switch (pdev->device)
1832 {
1833 case MPI_MANUFACTPAGE_DEVICEID_FC939X:
1834 case MPI_MANUFACTPAGE_DEVICEID_FC949X:
1835 ioc->errata_flag_1064 = 1;
1836 case MPI_MANUFACTPAGE_DEVICEID_FC909:
1837 case MPI_MANUFACTPAGE_DEVICEID_FC929:
1838 case MPI_MANUFACTPAGE_DEVICEID_FC919:
1839 case MPI_MANUFACTPAGE_DEVICEID_FC949E:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301841 break;
1842
1843 case MPI_MANUFACTPAGE_DEVICEID_FC929X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 if (revision < XL_929) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 /* 929X Chip Fix. Set Split transactions level
1846 * for PCIX. Set MOST bits to zero.
1847 */
1848 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1849 pcixcmd &= 0x8F;
1850 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1851 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 /* 929XL Chip Fix. Set MMRBC to 0x08.
1853 */
1854 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1855 pcixcmd |= 0x08;
1856 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1857 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301859 break;
1860
1861 case MPI_MANUFACTPAGE_DEVICEID_FC919X:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 /* 919X Chip Fix. Set Split transactions level
1863 * for PCIX. Set MOST bits to zero.
1864 */
1865 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1866 pcixcmd &= 0x8F;
1867 pci_write_config_byte(pdev, 0x6a, pcixcmd);
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001868 ioc->bus_type = FC;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301869 break;
1870
1871 case MPI_MANUFACTPAGE_DEVID_53C1030:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 /* 1030 Chip Fix. Disable Split transactions
1873 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
1874 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 if (revision < C0_1030) {
1876 pci_read_config_byte(pdev, 0x6a, &pcixcmd);
1877 pcixcmd &= 0x8F;
1878 pci_write_config_byte(pdev, 0x6a, pcixcmd);
1879 }
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301880
1881 case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
Moore, Eric Deana9b29372005-11-16 18:54:20 -07001882 ioc->bus_type = SPI;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301883 break;
1884
1885 case MPI_MANUFACTPAGE_DEVID_SAS1064:
1886 case MPI_MANUFACTPAGE_DEVID_SAS1068:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02001887 ioc->errata_flag_1064 = 1;
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05301888
1889 case MPI_MANUFACTPAGE_DEVID_SAS1064E:
1890 case MPI_MANUFACTPAGE_DEVID_SAS1068E:
1891 case MPI_MANUFACTPAGE_DEVID_SAS1078:
Eric Moore87cf8982006-06-27 16:09:26 -06001892 ioc->bus_type = SAS;
1893 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894
Prakash, Sathya23a274c2008-03-07 15:53:21 +05301895
Kashyap, Desaie3829682009-01-08 14:27:16 +05301896 switch (ioc->bus_type) {
1897
1898 case SAS:
1899 ioc->msi_enable = mpt_msi_enable_sas;
1900 break;
1901
1902 case SPI:
1903 ioc->msi_enable = mpt_msi_enable_spi;
1904 break;
1905
1906 case FC:
1907 ioc->msi_enable = mpt_msi_enable_fc;
1908 break;
1909
1910 default:
1911 ioc->msi_enable = 0;
1912 break;
1913 }
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06001914 if (ioc->errata_flag_1064)
1915 pci_disable_io_access(pdev);
1916
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 spin_lock_init(&ioc->FreeQlock);
1918
1919 /* Disable all! */
1920 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
1921 ioc->active = 0;
1922 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
1923
Prakash, Sathya07df8af2008-02-08 16:35:40 +05301924 /* Set IOC ptr in the pcidev's driver data. */
1925 pci_set_drvdata(ioc->pcidev, ioc);
1926
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 /* Set lookup ptr. */
1928 list_add_tail(&ioc->list, &ioc_list);
1929
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001930 /* Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 */
1932 mpt_detect_bound_ports(ioc, pdev);
1933
James Bottomleyc92f2222006-03-01 09:02:49 -06001934 if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
1935 CAN_SLEEP)) != 0){
Eric Moore29dd3602007-09-14 18:46:51 -06001936 printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
1937 ioc->name, r);
Eric Mooreba856d32006-07-11 17:34:01 -06001938
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 list_del(&ioc->list);
Moore, Eric335a9412006-01-17 17:06:23 -07001940 if (ioc->alt_ioc)
1941 ioc->alt_ioc->alt_ioc = NULL;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05301942 iounmap(ioc->memmap);
1943 if (r != -5)
1944 pci_release_selected_regions(pdev, ioc->bars);
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301945
1946 destroy_workqueue(ioc->reset_work_q);
1947 ioc->reset_work_q = NULL;
1948
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 kfree(ioc);
1950 pci_set_drvdata(pdev, NULL);
1951 return r;
1952 }
1953
1954 /* call per device driver probe entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06001955 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301956 if(MptDeviceDriverHandlers[cb_idx] &&
1957 MptDeviceDriverHandlers[cb_idx]->probe) {
1958 MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 }
1960 }
1961
1962#ifdef CONFIG_PROC_FS
1963 /*
1964 * Create "/proc/mpt/iocN" subdirectory entry for each MPT adapter.
1965 */
1966 dent = proc_mkdir(ioc->name, mpt_proc_root_dir);
1967 if (dent) {
1968 ent = create_proc_entry("info", S_IFREG|S_IRUGO, dent);
1969 if (ent) {
1970 ent->read_proc = procmpt_iocinfo_read;
1971 ent->data = ioc;
1972 }
1973 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, dent);
1974 if (ent) {
1975 ent->read_proc = procmpt_summary_read;
1976 ent->data = ioc;
1977 }
1978 }
1979#endif
1980
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05301981 if (!ioc->alt_ioc)
1982 queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
1983 msecs_to_jiffies(MPT_POLLING_INTERVAL));
1984
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 return 0;
1986}
1987
1988/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08001989/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001990 * mpt_detach - Remove a PCI intelligent MPT adapter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 */
1993
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04001994void
1995mpt_detach(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996{
1997 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
1998 char pname[32];
Prakash, Sathyaf606f572007-08-14 16:12:53 +05301999 u8 cb_idx;
Prakash, Sathyad54d48b2008-05-21 01:02:18 +05302000 unsigned long flags;
2001 struct workqueue_struct *wq;
2002
2003 /*
2004 * Stop polling ioc for fault condition
2005 */
2006 spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
2007 wq = ioc->reset_work_q;
2008 ioc->reset_work_q = NULL;
2009 spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
2010 cancel_delayed_work(&ioc->fault_reset_work);
2011 destroy_workqueue(wq);
2012
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013
2014 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
2015 remove_proc_entry(pname, NULL);
2016 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/info", ioc->name);
2017 remove_proc_entry(pname, NULL);
2018 sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name);
2019 remove_proc_entry(pname, NULL);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002020
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 /* call per device driver remove entry point */
Eric Moore8d6d83e2007-09-14 18:47:40 -06002022 for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302023 if(MptDeviceDriverHandlers[cb_idx] &&
2024 MptDeviceDriverHandlers[cb_idx]->remove) {
2025 MptDeviceDriverHandlers[cb_idx]->remove(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 }
2027 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002028
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 /* Disable interrupts! */
2030 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2031
2032 ioc->active = 0;
2033 synchronize_irq(pdev->irq);
2034
2035 /* Clear any lingering interrupt */
2036 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2037
2038 CHIPREG_READ32(&ioc->chip->IntStatus);
2039
2040 mpt_adapter_dispose(ioc);
2041
2042 pci_set_drvdata(pdev, NULL);
2043}
2044
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045/**************************************************************************
2046 * Power Management
2047 */
2048#ifdef CONFIG_PM
2049/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002050/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002051 * mpt_suspend - Fusion MPT base driver suspend routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002052 * @pdev: Pointer to pci_dev structure
2053 * @state: new state to enter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002055int
2056mpt_suspend(struct pci_dev *pdev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057{
2058 u32 device_state;
2059 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302061 device_state = pci_choose_state(pdev, state);
2062 printk(MYIOC_s_INFO_FMT "pci-suspend: pdev=0x%p, slot=%s, Entering "
2063 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2064 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065
2066 /* put ioc into READY_STATE */
2067 if(SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, CAN_SLEEP)) {
2068 printk(MYIOC_s_ERR_FMT
2069 "pci-suspend: IOC msg unit reset failed!\n", ioc->name);
2070 }
2071
2072 /* disable interrupts */
2073 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2074 ioc->active = 0;
2075
2076 /* Clear any lingering interrupt */
2077 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2078
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302079 free_irq(ioc->pci_irq, ioc);
James Bottomleyb8e3d3a2008-03-30 11:38:07 -05002080 if (ioc->msi_enable)
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302081 pci_disable_msi(ioc->pcidev);
2082 ioc->pci_irq = -1;
2083 pci_save_state(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 pci_disable_device(pdev);
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302085 pci_release_selected_regions(pdev, ioc->bars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 pci_set_power_state(pdev, device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 return 0;
2088}
2089
2090/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002091/**
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002092 * mpt_resume - Fusion MPT base driver resume routine.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002093 * @pdev: Pointer to pci_dev structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 */
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002095int
2096mpt_resume(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097{
2098 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
2099 u32 device_state = pdev->current_state;
2100 int recovery_state;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302101 int err;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002102
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302103 printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous "
2104 "operating state [D%d]\n", ioc->name, pdev, pci_name(pdev),
2105 device_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302107 pci_set_power_state(pdev, PCI_D0);
2108 pci_enable_wake(pdev, PCI_D0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 pci_restore_state(pdev);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302110 ioc->pcidev = pdev;
2111 err = mpt_mapresources(ioc);
2112 if (err)
2113 return err;
2114
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302115 if (ioc->dma_mask == DMA_BIT_MASK(64)) {
2116 if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078)
2117 ioc->add_sge = &mpt_add_sge_64bit_1078;
2118 else
2119 ioc->add_sge = &mpt_add_sge_64bit;
2120 ioc->add_chain = &mpt_add_chain_64bit;
2121 ioc->sg_addr_size = 8;
2122 } else {
2123
2124 ioc->add_sge = &mpt_add_sge;
2125 ioc->add_chain = &mpt_add_chain;
2126 ioc->sg_addr_size = 4;
2127 }
2128 ioc->SGE_size = sizeof(u32) + ioc->sg_addr_size;
2129
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302130 printk(MYIOC_s_INFO_FMT "pci-resume: ioc-state=0x%x,doorbell=0x%x\n",
2131 ioc->name, (mpt_GetIocState(ioc, 1) >> MPI_IOC_STATE_SHIFT),
2132 CHIPREG_READ32(&ioc->chip->Doorbell));
2133
2134 /*
2135 * Errata workaround for SAS pci express:
2136 * Upon returning to the D0 state, the contents of the doorbell will be
2137 * stale data, and this will incorrectly signal to the host driver that
2138 * the firmware is ready to process mpt commands. The workaround is
2139 * to issue a diagnostic reset.
2140 */
2141 if (ioc->bus_type == SAS && (pdev->device ==
2142 MPI_MANUFACTPAGE_DEVID_SAS1068E || pdev->device ==
2143 MPI_MANUFACTPAGE_DEVID_SAS1064E)) {
2144 if (KickStart(ioc, 1, CAN_SLEEP) < 0) {
2145 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover\n",
2146 ioc->name);
2147 goto out;
2148 }
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302149 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150
2151 /* bring ioc to operational state */
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302152 printk(MYIOC_s_INFO_FMT "Sending mpt_do_ioc_recovery\n", ioc->name);
2153 recovery_state = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
2154 CAN_SLEEP);
2155 if (recovery_state != 0)
2156 printk(MYIOC_s_WARN_FMT "pci-resume: Cannot recover, "
2157 "error:[%x]\n", ioc->name, recovery_state);
2158 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 printk(MYIOC_s_INFO_FMT
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302160 "pci-resume: success\n", ioc->name);
2161 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 return 0;
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302163
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164}
2165#endif
2166
James Bottomley4ff42a62006-05-17 18:06:52 -05002167static int
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302168mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
James Bottomley4ff42a62006-05-17 18:06:52 -05002169{
2170 if ((MptDriverClass[index] == MPTSPI_DRIVER &&
2171 ioc->bus_type != SPI) ||
2172 (MptDriverClass[index] == MPTFC_DRIVER &&
2173 ioc->bus_type != FC) ||
2174 (MptDriverClass[index] == MPTSAS_DRIVER &&
2175 ioc->bus_type != SAS))
2176 /* make sure we only call the relevant reset handler
2177 * for the bus */
2178 return 0;
2179 return (MptResetHandlers[index])(ioc, reset_phase);
2180}
2181
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002183/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 * mpt_do_ioc_recovery - Initialize or recover MPT adapter.
2185 * @ioc: Pointer to MPT adapter structure
2186 * @reason: Event word / reason
2187 * @sleepFlag: Use schedule if CAN_SLEEP else use udelay.
2188 *
2189 * This routine performs all the steps necessary to bring the IOC
2190 * to a OPERATIONAL state.
2191 *
2192 * This routine also pre-fetches the LAN MAC address of a Fibre Channel
2193 * MPT adapter.
2194 *
2195 * Returns:
2196 * 0 for success
2197 * -1 if failed to get board READY
2198 * -2 if READY but IOCFacts Failed
2199 * -3 if READY but PrimeIOCFifos Failed
2200 * -4 if READY but IOCInit Failed
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302201 * -5 if failed to enable_device and/or request_selected_regions
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302202 * -6 if failed to upload firmware
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 */
2204static int
2205mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
2206{
2207 int hard_reset_done = 0;
2208 int alt_ioc_ready = 0;
2209 int hard;
2210 int rc=0;
2211 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302212 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 int handlers;
2214 int ret = 0;
2215 int reset_alt_ioc_active = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002216 int irq_allocated = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302217 u8 *a;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218
Eric Moore29dd3602007-09-14 18:46:51 -06002219 printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
2220 reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221
2222 /* Disable reply interrupts (also blocks FreeQ) */
2223 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2224 ioc->active = 0;
2225
2226 if (ioc->alt_ioc) {
2227 if (ioc->alt_ioc->active)
2228 reset_alt_ioc_active = 1;
2229
2230 /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */
2231 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF);
2232 ioc->alt_ioc->active = 0;
2233 }
2234
2235 hard = 1;
2236 if (reason == MPT_HOSTEVENT_IOC_BRINGUP)
2237 hard = 0;
2238
2239 if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
2240 if (hard_reset_done == -4) {
Eric Moore29dd3602007-09-14 18:46:51 -06002241 printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
2242 ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243
2244 if (reset_alt_ioc_active && ioc->alt_ioc) {
2245 /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
Eric Moore29dd3602007-09-14 18:46:51 -06002246 dprintk(ioc, printk(MYIOC_s_INFO_FMT
2247 "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
Moore, Eric569b11d2006-01-13 16:25:29 -07002248 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 ioc->alt_ioc->active = 1;
2250 }
2251
2252 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002253 printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 }
2255 return -1;
2256 }
2257
2258 /* hard_reset_done = 0 if a soft reset was performed
2259 * and 1 if a hard reset was performed.
2260 */
2261 if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) {
2262 if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
2263 alt_ioc_ready = 1;
2264 else
Eric Moore29dd3602007-09-14 18:46:51 -06002265 printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 }
2267
2268 for (ii=0; ii<5; ii++) {
2269 /* Get IOC facts! Allow 5 retries */
2270 if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0)
2271 break;
2272 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002273
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274
2275 if (ii == 5) {
Eric Moore29dd3602007-09-14 18:46:51 -06002276 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2277 "Retry IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 ret = -2;
2279 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2280 MptDisplayIocCapabilities(ioc);
2281 }
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002282
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 if (alt_ioc_ready) {
2284 if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302285 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002286 "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 /* Retry - alt IOC was initialized once
2288 */
2289 rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
2290 }
2291 if (rc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302292 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002293 "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 alt_ioc_ready = 0;
2295 reset_alt_ioc_active = 0;
2296 } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
2297 MptDisplayIocCapabilities(ioc->alt_ioc);
2298 }
2299 }
2300
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302301 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) &&
2302 (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) {
2303 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2304 ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM |
2305 IORESOURCE_IO);
2306 if (pci_enable_device(ioc->pcidev))
2307 return -5;
2308 if (pci_request_selected_regions(ioc->pcidev, ioc->bars,
2309 "mpt"))
2310 return -5;
2311 }
2312
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002313 /*
2314 * Device is reset now. It must have de-asserted the interrupt line
2315 * (if it was asserted) and it should be safe to register for the
2316 * interrupt now.
2317 */
2318 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
2319 ioc->pci_irq = -1;
2320 if (ioc->pcidev->irq) {
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302321 if (ioc->msi_enable && !pci_enable_msi(ioc->pcidev))
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002322 printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002323 ioc->name);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302324 else
2325 ioc->msi_enable = 0;
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002326 rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
Eric Moore29dd3602007-09-14 18:46:51 -06002327 IRQF_SHARED, ioc->name, ioc);
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002328 if (rc < 0) {
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002329 printk(MYIOC_s_ERR_FMT "Unable to allocate "
Eric Moore29dd3602007-09-14 18:46:51 -06002330 "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302331 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002332 pci_disable_msi(ioc->pcidev);
2333 return -EBUSY;
2334 }
2335 irq_allocated = 1;
2336 ioc->pci_irq = ioc->pcidev->irq;
2337 pci_set_master(ioc->pcidev); /* ?? */
Eric Moore29dd3602007-09-14 18:46:51 -06002338 dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
2339 "%d\n", ioc->name, ioc->pcidev->irq));
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002340 }
2341 }
2342
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 /* Prime reply & request queues!
2344 * (mucho alloc's) Must be done prior to
2345 * init as upper addresses are needed for init.
2346 * If fails, continue with alt-ioc processing
2347 */
2348 if ((ret == 0) && ((rc = PrimeIocFifos(ioc)) != 0))
2349 ret = -3;
2350
2351 /* May need to check/upload firmware & data here!
2352 * If fails, continue with alt-ioc processing
2353 */
2354 if ((ret == 0) && ((rc = SendIocInit(ioc, sleepFlag)) != 0))
2355 ret = -4;
2356// NEW!
2357 if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
Eric Moore29dd3602007-09-14 18:46:51 -06002358 printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
2359 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 alt_ioc_ready = 0;
2361 reset_alt_ioc_active = 0;
2362 }
2363
2364 if (alt_ioc_ready) {
2365 if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
2366 alt_ioc_ready = 0;
2367 reset_alt_ioc_active = 0;
Eric Moore29dd3602007-09-14 18:46:51 -06002368 printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
2369 ioc->alt_ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 }
2371 }
2372
2373 if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
2374 if (ioc->upload_fw) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302375 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002376 "firmware upload required!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377
2378 /* Controller is not operational, cannot do upload
2379 */
2380 if (ret == 0) {
2381 rc = mpt_do_upload(ioc, sleepFlag);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002382 if (rc == 0) {
2383 if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
2384 /*
2385 * Maintain only one pointer to FW memory
2386 * so there will not be two attempt to
2387 * downloadboot onboard dual function
2388 * chips (mpt_adapter_disable,
2389 * mpt_diag_reset)
2390 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05302391 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002392 "mpt_upload: alt_%s has cached_fw=%p \n",
2393 ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302394 ioc->cached_fw = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002395 }
2396 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002397 printk(MYIOC_s_WARN_FMT
2398 "firmware upload failure!\n", ioc->name);
Prakash, Sathya4d4109d2008-03-07 16:19:50 +05302399 ret = -6;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 }
2402 }
2403 }
2404
Kashyap, Desaifd761752009-05-29 16:39:06 +05302405 /* Enable MPT base driver management of EventNotification
2406 * and EventAck handling.
2407 */
2408 if ((ret == 0) && (!ioc->facts.EventState)) {
2409 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2410 "SendEventNotification\n",
2411 ioc->name));
2412 ret = SendEventNotification(ioc, 1, sleepFlag); /* 1=Enable */
2413 }
2414
2415 if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState)
2416 rc = SendEventNotification(ioc->alt_ioc, 1, sleepFlag);
2417
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 if (ret == 0) {
2419 /* Enable! (reply interrupt) */
Moore, Eric569b11d2006-01-13 16:25:29 -07002420 CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 ioc->active = 1;
2422 }
Kashyap, Desaifd761752009-05-29 16:39:06 +05302423 if (rc == 0) { /* alt ioc */
2424 if (reset_alt_ioc_active && ioc->alt_ioc) {
2425 /* (re)Enable alt-IOC! (reply interrupt) */
2426 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "alt-ioc"
2427 "reply irq re-enabled\n",
2428 ioc->alt_ioc->name));
2429 CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask,
2430 MPI_HIM_DIM);
2431 ioc->alt_ioc->active = 1;
2432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 }
2434
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002436 /* Add additional "reason" check before call to GetLanConfigPages
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 * (combined with GetIoUnitPage2 call). This prevents a somewhat
2438 * recursive scenario; GetLanConfigPages times out, timer expired
2439 * routine calls HardResetHandler, which calls into here again,
2440 * and we try GetLanConfigPages again...
2441 */
2442 if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002443
2444 /*
2445 * Initalize link list for inactive raid volumes.
2446 */
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01002447 mutex_init(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07002448 INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
2449
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002450 if (ioc->bus_type == SAS) {
2451
2452 /* clear persistency table */
2453 if(ioc->facts.IOCExceptions &
2454 MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) {
2455 ret = mptbase_sas_persist_operation(ioc,
2456 MPI_SAS_OP_CLEAR_NOT_PRESENT);
2457 if(ret != 0)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002458 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002459 }
2460
2461 /* Find IM volumes
2462 */
2463 mpt_findImVolumes(ioc);
2464
2465 } else if (ioc->bus_type == FC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
2467 (ioc->lan_cnfg_page0.Header.PageLength == 0)) {
2468 /*
2469 * Pre-fetch the ports LAN MAC address!
2470 * (LANPage1_t stuff)
2471 */
2472 (void) GetLanConfigPages(ioc);
Prakash, Sathya436ace72007-07-24 15:42:08 +05302473 a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
2474 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002475 "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
2476 ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
Prakash, Sathya436ace72007-07-24 15:42:08 +05302477
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 }
2479 } else {
2480 /* Get NVRAM and adapter maximums from SPP 0 and 2
2481 */
2482 mpt_GetScsiPortSettings(ioc, 0);
2483
2484 /* Get version and length of SDP 1
2485 */
2486 mpt_readScsiDevicePageHeaders(ioc, 0);
2487
2488 /* Find IM volumes
2489 */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002490 if (ioc->facts.MsgVersion >= MPI_VERSION_01_02)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 mpt_findImVolumes(ioc);
2492
2493 /* Check, and possibly reset, the coalescing value
2494 */
2495 mpt_read_ioc_pg_1(ioc);
2496
2497 mpt_read_ioc_pg_4(ioc);
2498 }
2499
2500 GetIoUnitPage2(ioc);
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302501 mpt_get_manufacturing_pg_0(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 }
2503
2504 /*
2505 * Call each currently registered protocol IOC reset handler
2506 * with post-reset indication.
2507 * NOTE: If we're doing _IOC_BRINGUP, there can be no
2508 * MptResetHandlers[] registered yet.
2509 */
2510 if (hard_reset_done) {
2511 rc = handlers = 0;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302512 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
2513 if ((ret == 0) && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302514 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002515 "Calling IOC post_reset handler #%d\n",
2516 ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302517 rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 handlers++;
2519 }
2520
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302521 if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302522 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002523 "Calling IOC post_reset handler #%d\n",
2524 ioc->alt_ioc->name, cb_idx));
Prakash, Sathyaf606f572007-08-14 16:12:53 +05302525 rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 handlers++;
2527 }
2528 }
2529 /* FIXME? Examine results here? */
2530 }
2531
Eric Moore0ccdb002006-07-11 17:33:13 -06002532 out:
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002533 if ((ret != 0) && irq_allocated) {
2534 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302535 if (ioc->msi_enable)
Vivek Goyal9bf0a282006-04-27 02:33:13 -07002536 pci_disable_msi(ioc->pcidev);
2537 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 return ret;
2539}
2540
2541/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002542/**
2543 * mpt_detect_bound_ports - Search for matching PCI bus/dev_function
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 * @ioc: Pointer to MPT adapter structure
2545 * @pdev: Pointer to (struct pci_dev) structure
2546 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002547 * Search for PCI bus/dev_function which matches
2548 * PCI bus/dev_function (+/-1) for newly discovered 929,
2549 * 929X, 1030 or 1035.
2550 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 * If match on PCI dev_function +/-1 is found, bind the two MPT adapters
2552 * using alt_ioc pointer fields in their %MPT_ADAPTER structures.
2553 */
2554static void
2555mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
2556{
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002557 struct pci_dev *peer=NULL;
2558 unsigned int slot = PCI_SLOT(pdev->devfn);
2559 unsigned int func = PCI_FUNC(pdev->devfn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 MPT_ADAPTER *ioc_srch;
2561
Prakash, Sathya436ace72007-07-24 15:42:08 +05302562 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002563 " searching for devfn match on %x or %x\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002564 ioc->name, pci_name(pdev), pdev->bus->number,
2565 pdev->devfn, func-1, func+1));
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002566
2567 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
2568 if (!peer) {
2569 peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func+1));
2570 if (!peer)
2571 return;
2572 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573
2574 list_for_each_entry(ioc_srch, &ioc_list, list) {
2575 struct pci_dev *_pcidev = ioc_srch->pcidev;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002576 if (_pcidev == peer) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 /* Paranoia checks */
2578 if (ioc->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002579 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002580 ioc->name, ioc->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 break;
2582 } else if (ioc_srch->alt_ioc != NULL) {
Eric Moore29dd3602007-09-14 18:46:51 -06002583 printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002584 ioc_srch->name, ioc_srch->alt_ioc->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 break;
2586 }
Eric Moore29dd3602007-09-14 18:46:51 -06002587 dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002588 ioc->name, ioc_srch->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 ioc_srch->alt_ioc = ioc;
2590 ioc->alt_ioc = ioc_srch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 }
2592 }
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04002593 pci_dev_put(peer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594}
2595
2596/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002597/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 * mpt_adapter_disable - Disable misbehaving MPT adapter.
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002599 * @ioc: Pointer to MPT adapter structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 */
2601static void
2602mpt_adapter_disable(MPT_ADAPTER *ioc)
2603{
2604 int sz;
2605 int ret;
2606
2607 if (ioc->cached_fw != NULL) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05302608 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002609 "adapter\n", __func__, ioc->name));
Prakash, Sathya984621b2008-01-11 14:42:17 +05302610 if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
2611 ioc->cached_fw, CAN_SLEEP)) < 0) {
2612 printk(MYIOC_s_WARN_FMT
2613 ": firmware downloadboot failure (%d)!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002614 ioc->name, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 }
2616 }
2617
2618 /* Disable adapter interrupts! */
2619 CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
2620 ioc->active = 0;
2621 /* Clear any lingering interrupt */
2622 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
2623
2624 if (ioc->alloc != NULL) {
2625 sz = ioc->alloc_sz;
Eric Moore29dd3602007-09-14 18:46:51 -06002626 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
2627 ioc->name, ioc->alloc, ioc->alloc_sz));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 pci_free_consistent(ioc->pcidev, sz,
2629 ioc->alloc, ioc->alloc_dma);
2630 ioc->reply_frames = NULL;
2631 ioc->req_frames = NULL;
2632 ioc->alloc = NULL;
2633 ioc->alloc_total -= sz;
2634 }
2635
2636 if (ioc->sense_buf_pool != NULL) {
2637 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
2638 pci_free_consistent(ioc->pcidev, sz,
2639 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
2640 ioc->sense_buf_pool = NULL;
2641 ioc->alloc_total -= sz;
2642 }
2643
2644 if (ioc->events != NULL){
2645 sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
2646 kfree(ioc->events);
2647 ioc->events = NULL;
2648 ioc->alloc_total -= sz;
2649 }
2650
Prakash, Sathya984621b2008-01-11 14:42:17 +05302651 mpt_free_fw_memory(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002653 kfree(ioc->spi_data.nvram);
Eric Mooreb506ade2007-01-29 09:45:37 -07002654 mpt_inactive_raid_list_free(ioc);
2655 kfree(ioc->raid_data.pIocPg2);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002656 kfree(ioc->raid_data.pIocPg3);
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002657 ioc->spi_data.nvram = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06002658 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659
2660 if (ioc->spi_data.pIocPg4 != NULL) {
2661 sz = ioc->spi_data.IocPg4Sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05302662 pci_free_consistent(ioc->pcidev, sz,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 ioc->spi_data.pIocPg4,
2664 ioc->spi_data.IocPg4_dma);
2665 ioc->spi_data.pIocPg4 = NULL;
2666 ioc->alloc_total -= sz;
2667 }
2668
2669 if (ioc->ReqToChain != NULL) {
2670 kfree(ioc->ReqToChain);
2671 kfree(ioc->RequestNB);
2672 ioc->ReqToChain = NULL;
2673 }
2674
Moore, Eric Dean d485eb82005-05-11 17:37:26 -06002675 kfree(ioc->ChainToChain);
2676 ioc->ChainToChain = NULL;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002677
2678 if (ioc->HostPageBuffer != NULL) {
2679 if((ret = mpt_host_page_access_control(ioc,
2680 MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06002681 printk(MYIOC_s_ERR_FMT
2682 "host page buffers free failed (%d)!\n",
2683 ioc->name, ret);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002684 }
Eric Moore29dd3602007-09-14 18:46:51 -06002685 dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002686 ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
2687 pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
Eric Moore29dd3602007-09-14 18:46:51 -06002688 ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002689 ioc->HostPageBuffer = NULL;
2690 ioc->HostPageBuffer_sz = 0;
2691 ioc->alloc_total -= ioc->HostPageBuffer_sz;
2692 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693}
2694
2695/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002696/**
2697 * mpt_adapter_dispose - Free all resources associated with an MPT adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 * @ioc: Pointer to MPT adapter structure
2699 *
2700 * This routine unregisters h/w resources and frees all alloc'd memory
2701 * associated with a MPT adapter structure.
2702 */
2703static void
2704mpt_adapter_dispose(MPT_ADAPTER *ioc)
2705{
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002706 int sz_first, sz_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002708 if (ioc == NULL)
2709 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002711 sz_first = ioc->alloc_total;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002713 mpt_adapter_disable(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002715 if (ioc->pci_irq != -1) {
2716 free_irq(ioc->pci_irq, ioc);
Prakash, Sathya23a274c2008-03-07 15:53:21 +05302717 if (ioc->msi_enable)
Christoph Hellwig4ddce142006-01-17 13:44:29 +00002718 pci_disable_msi(ioc->pcidev);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002719 ioc->pci_irq = -1;
2720 }
2721
2722 if (ioc->memmap != NULL) {
2723 iounmap(ioc->memmap);
2724 ioc->memmap = NULL;
2725 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726
Prakash, Sathyae78d5b82008-02-08 22:05:35 +05302727 pci_disable_device(ioc->pcidev);
2728 pci_release_selected_regions(ioc->pcidev, ioc->bars);
2729
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730#if defined(CONFIG_MTRR) && 0
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002731 if (ioc->mtrr_reg > 0) {
2732 mtrr_del(ioc->mtrr_reg, 0, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002733 dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002734 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735#endif
2736
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002737 /* Zap the adapter lookup ptr! */
2738 list_del(&ioc->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002740 sz_last = ioc->alloc_total;
Eric Moore29dd3602007-09-14 18:46:51 -06002741 dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
2742 ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
Moore, Eric335a9412006-01-17 17:06:23 -07002743
2744 if (ioc->alt_ioc)
2745 ioc->alt_ioc->alt_ioc = NULL;
2746
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002747 kfree(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748}
2749
2750/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002751/**
2752 * MptDisplayIocCapabilities - Disply IOC's capabilities.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 * @ioc: Pointer to MPT adapter structure
2754 */
2755static void
2756MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
2757{
2758 int i = 0;
2759
2760 printk(KERN_INFO "%s: ", ioc->name);
Prakash, Sathyaef1d8df2007-07-17 14:18:41 +05302761 if (ioc->prod_name)
2762 printk("%s: ", ioc->prod_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 printk("Capabilities={");
2764
2765 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
2766 printk("Initiator");
2767 i++;
2768 }
2769
2770 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2771 printk("%sTarget", i ? "," : "");
2772 i++;
2773 }
2774
2775 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
2776 printk("%sLAN", i ? "," : "");
2777 i++;
2778 }
2779
2780#if 0
2781 /*
2782 * This would probably evoke more questions than it's worth
2783 */
2784 if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
2785 printk("%sLogBusAddr", i ? "," : "");
2786 i++;
2787 }
2788#endif
2789
2790 printk("}\n");
2791}
2792
2793/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002794/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 * MakeIocReady - Get IOC to a READY state, using KickStart if needed.
2796 * @ioc: Pointer to MPT_ADAPTER structure
2797 * @force: Force hard KickStart of IOC
2798 * @sleepFlag: Specifies whether the process can sleep
2799 *
2800 * Returns:
2801 * 1 - DIAG reset and READY
2802 * 0 - READY initially OR soft reset and READY
2803 * -1 - Any failure on KickStart
2804 * -2 - Msg Unit Reset Failed
2805 * -3 - IO Unit Reset Failed
2806 * -4 - IOC owned by a PEER
2807 */
2808static int
2809MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
2810{
2811 u32 ioc_state;
2812 int statefault = 0;
2813 int cntdn;
2814 int hard_reset_done = 0;
2815 int r;
2816 int ii;
2817 int whoinit;
2818
2819 /* Get current [raw] IOC state */
2820 ioc_state = mpt_GetIocState(ioc, 0);
Eric Moore29dd3602007-09-14 18:46:51 -06002821 dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822
2823 /*
2824 * Check to see if IOC got left/stuck in doorbell handshake
2825 * grip of death. If so, hard reset the IOC.
2826 */
2827 if (ioc_state & MPI_DOORBELL_ACTIVE) {
2828 statefault = 1;
2829 printk(MYIOC_s_WARN_FMT "Unexpected doorbell active!\n",
2830 ioc->name);
2831 }
2832
2833 /* Is it already READY? */
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002834 if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 return 0;
2836
2837 /*
2838 * Check to see if IOC is in FAULT state.
2839 */
2840 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
2841 statefault = 2;
2842 printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002843 ioc->name);
2844 printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
2845 ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 }
2847
2848 /*
2849 * Hmmm... Did it get left operational?
2850 */
2851 if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05302852 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 ioc->name));
2854
2855 /* Check WhoInit.
2856 * If PCI Peer, exit.
2857 * Else, if no fault conditions are present, issue a MessageUnitReset
2858 * Else, fall through to KickStart case
2859 */
2860 whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
Eric Moore29dd3602007-09-14 18:46:51 -06002861 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
2862 "whoinit 0x%x statefault %d force %d\n",
2863 ioc->name, whoinit, statefault, force));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 if (whoinit == MPI_WHOINIT_PCI_PEER)
2865 return -4;
2866 else {
2867 if ((statefault == 0 ) && (force == 0)) {
2868 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
2869 return 0;
2870 }
2871 statefault = 3;
2872 }
2873 }
2874
2875 hard_reset_done = KickStart(ioc, statefault||force, sleepFlag);
2876 if (hard_reset_done < 0)
2877 return -1;
2878
2879 /*
2880 * Loop here waiting for IOC to come READY.
2881 */
2882 ii = 0;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02002883 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884
2885 while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
2886 if (ioc_state == MPI_IOC_STATE_OPERATIONAL) {
2887 /*
2888 * BIOS or previous driver load left IOC in OP state.
2889 * Reset messaging FIFOs.
2890 */
2891 if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) != 0) {
2892 printk(MYIOC_s_ERR_FMT "IOC msg unit reset failed!\n", ioc->name);
2893 return -2;
2894 }
2895 } else if (ioc_state == MPI_IOC_STATE_RESET) {
2896 /*
2897 * Something is wrong. Try to get IOC back
2898 * to a known state.
2899 */
2900 if ((r = SendIocReset(ioc, MPI_FUNCTION_IO_UNIT_RESET, sleepFlag)) != 0) {
2901 printk(MYIOC_s_ERR_FMT "IO unit reset failed!\n", ioc->name);
2902 return -3;
2903 }
2904 }
2905
2906 ii++; cntdn--;
2907 if (!cntdn) {
2908 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
2909 ioc->name, (int)((ii+5)/HZ));
2910 return -ETIME;
2911 }
2912
2913 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05002914 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 } else {
2916 mdelay (1); /* 1 msec delay */
2917 }
2918
2919 }
2920
2921 if (statefault < 3) {
2922 printk(MYIOC_s_INFO_FMT "Recovered from %s\n",
2923 ioc->name,
2924 statefault==1 ? "stuck handshake" : "IOC FAULT");
2925 }
2926
2927 return hard_reset_done;
2928}
2929
2930/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002931/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 * mpt_GetIocState - Get the current state of a MPT adapter.
2933 * @ioc: Pointer to MPT_ADAPTER structure
2934 * @cooked: Request raw or cooked IOC state
2935 *
2936 * Returns all IOC Doorbell register bits if cooked==0, else just the
2937 * Doorbell bits in MPI_IOC_STATE_MASK.
2938 */
2939u32
2940mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
2941{
2942 u32 s, sc;
2943
2944 /* Get! */
2945 s = CHIPREG_READ32(&ioc->chip->Doorbell);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 sc = s & MPI_IOC_STATE_MASK;
2947
2948 /* Save! */
2949 ioc->last_state = sc;
2950
2951 return cooked ? sc : s;
2952}
2953
2954/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08002955/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 * GetIocFacts - Send IOCFacts request to MPT adapter.
2957 * @ioc: Pointer to MPT_ADAPTER structure
2958 * @sleepFlag: Specifies whether the process can sleep
2959 * @reason: If recovery, only update facts.
2960 *
2961 * Returns 0 for success, non-zero for failure.
2962 */
2963static int
2964GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
2965{
2966 IOCFacts_t get_facts;
2967 IOCFactsReply_t *facts;
2968 int r;
2969 int req_sz;
2970 int reply_sz;
2971 int sz;
2972 u32 status, vv;
2973 u8 shiftFactor=1;
2974
2975 /* IOC *must* NOT be in RESET state! */
2976 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06002977 printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
2978 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 return -44;
2980 }
2981
2982 facts = &ioc->facts;
2983
2984 /* Destination (reply area)... */
2985 reply_sz = sizeof(*facts);
2986 memset(facts, 0, reply_sz);
2987
2988 /* Request area (get_facts on the stack right now!) */
2989 req_sz = sizeof(get_facts);
2990 memset(&get_facts, 0, req_sz);
2991
2992 get_facts.Function = MPI_FUNCTION_IOC_FACTS;
2993 /* Assert: All other get_facts fields are zero! */
2994
Prakash, Sathya436ace72007-07-24 15:42:08 +05302995 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02002996 "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 ioc->name, req_sz, reply_sz));
2998
2999 /* No non-zero fields in the get_facts request are greater than
3000 * 1 byte in size, so we can just fire it off as is.
3001 */
3002 r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts,
3003 reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag);
3004 if (r != 0)
3005 return r;
3006
3007 /*
3008 * Now byte swap (GRRR) the necessary fields before any further
3009 * inspection of reply contents.
3010 *
3011 * But need to do some sanity checks on MsgLength (byte) field
3012 * to make sure we don't zero IOC's req_sz!
3013 */
3014 /* Did we get a valid reply? */
3015 if (facts->MsgLength > offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32)) {
3016 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3017 /*
3018 * If not been here, done that, save off first WhoInit value
3019 */
3020 if (ioc->FirstWhoInit == WHOINIT_UNKNOWN)
3021 ioc->FirstWhoInit = facts->WhoInit;
3022 }
3023
3024 facts->MsgVersion = le16_to_cpu(facts->MsgVersion);
3025 facts->MsgContext = le32_to_cpu(facts->MsgContext);
3026 facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions);
3027 facts->IOCStatus = le16_to_cpu(facts->IOCStatus);
3028 facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo);
Christoph Hellwig637fa992005-08-18 16:25:44 +02003029 status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 /* CHECKME! IOCStatus, IOCLogInfo */
3031
3032 facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth);
3033 facts->RequestFrameSize = le16_to_cpu(facts->RequestFrameSize);
3034
3035 /*
3036 * FC f/w version changed between 1.1 and 1.2
3037 * Old: u16{Major(4),Minor(4),SubMinor(8)}
3038 * New: u32{Major(8),Minor(8),Unit(8),Dev(8)}
3039 */
3040 if (facts->MsgVersion < 0x0102) {
3041 /*
3042 * Handle old FC f/w style, convert to new...
3043 */
3044 u16 oldv = le16_to_cpu(facts->Reserved_0101_FWVersion);
3045 facts->FWVersion.Word =
3046 ((oldv<<12) & 0xFF000000) |
3047 ((oldv<<8) & 0x000FFF00);
3048 } else
3049 facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
3050
3051 facts->ProductID = le16_to_cpu(facts->ProductID);
Eric Mooreb506ade2007-01-29 09:45:37 -07003052 if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
3053 > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
3054 ioc->ir_firmware = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 facts->CurrentHostMfaHighAddr =
3056 le32_to_cpu(facts->CurrentHostMfaHighAddr);
3057 facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
3058 facts->CurrentSenseBufferHighAddr =
3059 le32_to_cpu(facts->CurrentSenseBufferHighAddr);
3060 facts->CurReplyFrameSize =
3061 le16_to_cpu(facts->CurReplyFrameSize);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003062 facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063
3064 /*
3065 * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx
3066 * Older MPI-1.00.xx struct had 13 dwords, and enlarged
3067 * to 14 in MPI-1.01.0x.
3068 */
3069 if (facts->MsgLength >= (offsetof(IOCFactsReply_t,FWImageSize) + 7)/4 &&
3070 facts->MsgVersion > 0x0100) {
3071 facts->FWImageSize = le32_to_cpu(facts->FWImageSize);
3072 }
3073
3074 sz = facts->FWImageSize;
3075 if ( sz & 0x01 )
3076 sz += 1;
3077 if ( sz & 0x02 )
3078 sz += 2;
3079 facts->FWImageSize = sz;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003080
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 if (!facts->RequestFrameSize) {
3082 /* Something is wrong! */
3083 printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n",
3084 ioc->name);
3085 return -55;
3086 }
3087
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04003088 r = sz = facts->BlockSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 vv = ((63 / (sz * 4)) + 1) & 0x03;
3090 ioc->NB_for_64_byte_frame = vv;
3091 while ( sz )
3092 {
3093 shiftFactor++;
3094 sz = sz >> 1;
3095 }
3096 ioc->NBShiftFactor = shiftFactor;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303097 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06003098 "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
3099 ioc->name, vv, shiftFactor, r));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003100
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
3102 /*
3103 * Set values for this IOC's request & reply frame sizes,
3104 * and request & reply queue depths...
3105 */
3106 ioc->req_sz = min(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4);
3107 ioc->req_depth = min_t(int, MPT_MAX_REQ_DEPTH, facts->GlobalCredits);
3108 ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
3109 ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
3110
Prakash, Sathya436ace72007-07-24 15:42:08 +05303111 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303113 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz =%3d, req_depth =%4d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 ioc->name, ioc->req_sz, ioc->req_depth));
3115
3116 /* Get port facts! */
3117 if ( (r = GetPortFacts(ioc, 0, sleepFlag)) != 0 )
3118 return r;
3119 }
3120 } else {
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003121 printk(MYIOC_s_ERR_FMT
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n",
3123 ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t,
3124 RequestFrameSize)/sizeof(u32)));
3125 return -66;
3126 }
3127
3128 return 0;
3129}
3130
3131/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003132/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 * GetPortFacts - Send PortFacts request to MPT adapter.
3134 * @ioc: Pointer to MPT_ADAPTER structure
3135 * @portnum: Port number
3136 * @sleepFlag: Specifies whether the process can sleep
3137 *
3138 * Returns 0 for success, non-zero for failure.
3139 */
3140static int
3141GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3142{
3143 PortFacts_t get_pfacts;
3144 PortFactsReply_t *pfacts;
3145 int ii;
3146 int req_sz;
3147 int reply_sz;
Eric Moore793955f2007-01-29 09:42:20 -07003148 int max_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149
3150 /* IOC *must* NOT be in RESET state! */
3151 if (ioc->last_state == MPI_IOC_STATE_RESET) {
Eric Moore29dd3602007-09-14 18:46:51 -06003152 printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
3153 ioc->name, ioc->last_state );
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 return -4;
3155 }
3156
3157 pfacts = &ioc->pfacts[portnum];
3158
3159 /* Destination (reply area)... */
3160 reply_sz = sizeof(*pfacts);
3161 memset(pfacts, 0, reply_sz);
3162
3163 /* Request area (get_pfacts on the stack right now!) */
3164 req_sz = sizeof(get_pfacts);
3165 memset(&get_pfacts, 0, req_sz);
3166
3167 get_pfacts.Function = MPI_FUNCTION_PORT_FACTS;
3168 get_pfacts.PortNumber = portnum;
3169 /* Assert: All other get_pfacts fields are zero! */
3170
Prakash, Sathya436ace72007-07-24 15:42:08 +05303171 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 ioc->name, portnum));
3173
3174 /* No non-zero fields in the get_pfacts request are greater than
3175 * 1 byte in size, so we can just fire it off as is.
3176 */
3177 ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts,
3178 reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag);
3179 if (ii != 0)
3180 return ii;
3181
3182 /* Did we get a valid reply? */
3183
3184 /* Now byte swap the necessary fields in the response. */
3185 pfacts->MsgContext = le32_to_cpu(pfacts->MsgContext);
3186 pfacts->IOCStatus = le16_to_cpu(pfacts->IOCStatus);
3187 pfacts->IOCLogInfo = le32_to_cpu(pfacts->IOCLogInfo);
3188 pfacts->MaxDevices = le16_to_cpu(pfacts->MaxDevices);
3189 pfacts->PortSCSIID = le16_to_cpu(pfacts->PortSCSIID);
3190 pfacts->ProtocolFlags = le16_to_cpu(pfacts->ProtocolFlags);
3191 pfacts->MaxPostedCmdBuffers = le16_to_cpu(pfacts->MaxPostedCmdBuffers);
3192 pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
3193 pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
3194
Eric Moore793955f2007-01-29 09:42:20 -07003195 max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
3196 pfacts->MaxDevices;
3197 ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
3198 ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
3199
3200 /*
3201 * Place all the devices on channels
3202 *
3203 * (for debuging)
3204 */
3205 if (mpt_channel_mapping) {
3206 ioc->devices_per_bus = 1;
3207 ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
3208 }
3209
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 return 0;
3211}
3212
3213/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003214/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 * SendIocInit - Send IOCInit request to MPT adapter.
3216 * @ioc: Pointer to MPT_ADAPTER structure
3217 * @sleepFlag: Specifies whether the process can sleep
3218 *
3219 * Send IOCInit followed by PortEnable to bring IOC to OPERATIONAL state.
3220 *
3221 * Returns 0 for success, non-zero for failure.
3222 */
3223static int
3224SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
3225{
3226 IOCInit_t ioc_init;
3227 MPIDefaultReply_t init_reply;
3228 u32 state;
3229 int r;
3230 int count;
3231 int cntdn;
3232
3233 memset(&ioc_init, 0, sizeof(ioc_init));
3234 memset(&init_reply, 0, sizeof(init_reply));
3235
3236 ioc_init.WhoInit = MPI_WHOINIT_HOST_DRIVER;
3237 ioc_init.Function = MPI_FUNCTION_IOC_INIT;
3238
3239 /* If we are in a recovery mode and we uploaded the FW image,
3240 * then this pointer is not NULL. Skip the upload a second time.
3241 * Set this flag if cached_fw set for either IOC.
3242 */
3243 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
3244 ioc->upload_fw = 1;
3245 else
3246 ioc->upload_fw = 0;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303247 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 ioc->name, ioc->upload_fw, ioc->facts.Flags));
3249
Eric Moore793955f2007-01-29 09:42:20 -07003250 ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
3251 ioc_init.MaxBuses = (U8)ioc->number_of_buses;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303252 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003253 ioc->name, ioc->facts.MsgVersion));
3254 if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
3255 // set MsgVersion and HeaderVersion host driver was built with
3256 ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION);
3257 ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003259 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) {
3260 ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE;
3261 } else if(mpt_host_page_alloc(ioc, &ioc_init))
3262 return -99;
3263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */
3265
3266 if (sizeof(dma_addr_t) == sizeof(u64)) {
3267 /* Save the upper 32-bits of the request
3268 * (reply) and sense buffers.
3269 */
3270 ioc_init.HostMfaHighAddr = cpu_to_le32((u32)((u64)ioc->alloc_dma >> 32));
3271 ioc_init.SenseBufferHighAddr = cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32));
3272 } else {
3273 /* Force 32-bit addressing */
3274 ioc_init.HostMfaHighAddr = cpu_to_le32(0);
3275 ioc_init.SenseBufferHighAddr = cpu_to_le32(0);
3276 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003277
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278 ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr;
3279 ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003280 ioc->facts.MaxDevices = ioc_init.MaxDevices;
3281 ioc->facts.MaxBuses = ioc_init.MaxBuses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282
Prakash, Sathya436ace72007-07-24 15:42:08 +05303283 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 ioc->name, &ioc_init));
3285
3286 r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
3287 sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003288 if (r != 0) {
3289 printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 return r;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003291 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292
3293 /* No need to byte swap the multibyte fields in the reply
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003294 * since we don't even look at its contents.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 */
3296
Prakash, Sathya436ace72007-07-24 15:42:08 +05303297 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 ioc->name, &ioc_init));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003299
3300 if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
3301 printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 return r;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003303 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304
3305 /* YIKES! SUPER IMPORTANT!!!
3306 * Poll IocState until _OPERATIONAL while IOC is doing
3307 * LoopInit and TargetDiscovery!
3308 */
3309 count = 0;
3310 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 60; /* 60 seconds */
3311 state = mpt_GetIocState(ioc, 1);
3312 while (state != MPI_IOC_STATE_OPERATIONAL && --cntdn) {
3313 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003314 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 } else {
3316 mdelay(1);
3317 }
3318
3319 if (!cntdn) {
3320 printk(MYIOC_s_ERR_FMT "Wait IOC_OP state timeout(%d)!\n",
3321 ioc->name, (int)((count+5)/HZ));
3322 return -9;
3323 }
3324
3325 state = mpt_GetIocState(ioc, 1);
3326 count++;
3327 }
Eric Moore29dd3602007-09-14 18:46:51 -06003328 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 ioc->name, count));
3330
Eric Mooreba856d32006-07-11 17:34:01 -06003331 ioc->aen_event_read_flag=0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 return r;
3333}
3334
3335/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003336/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337 * SendPortEnable - Send PortEnable request to MPT adapter port.
3338 * @ioc: Pointer to MPT_ADAPTER structure
3339 * @portnum: Port number to enable
3340 * @sleepFlag: Specifies whether the process can sleep
3341 *
3342 * Send PortEnable to bring IOC to OPERATIONAL state.
3343 *
3344 * Returns 0 for success, non-zero for failure.
3345 */
3346static int
3347SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
3348{
3349 PortEnable_t port_enable;
3350 MPIDefaultReply_t reply_buf;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003351 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 int req_sz;
3353 int reply_sz;
3354
3355 /* Destination... */
3356 reply_sz = sizeof(MPIDefaultReply_t);
3357 memset(&reply_buf, 0, reply_sz);
3358
3359 req_sz = sizeof(PortEnable_t);
3360 memset(&port_enable, 0, req_sz);
3361
3362 port_enable.Function = MPI_FUNCTION_PORT_ENABLE;
3363 port_enable.PortNumber = portnum;
3364/* port_enable.ChainOffset = 0; */
3365/* port_enable.MsgFlags = 0; */
3366/* port_enable.MsgContext = 0; */
3367
Prakash, Sathya436ace72007-07-24 15:42:08 +05303368 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 ioc->name, portnum, &port_enable));
3370
3371 /* RAID FW may take a long time to enable
3372 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003373 if (ioc->ir_firmware || ioc->bus_type == SAS) {
Moore, Eric432b4c82006-01-16 18:53:11 -07003374 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3375 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3376 300 /*seconds*/, sleepFlag);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003377 } else {
Moore, Eric432b4c82006-01-16 18:53:11 -07003378 rc = mpt_handshake_req_reply_wait(ioc, req_sz,
3379 (u32*)&port_enable, reply_sz, (u16*)&reply_buf,
3380 30 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003382 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383}
3384
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003385/**
3386 * mpt_alloc_fw_memory - allocate firmware memory
3387 * @ioc: Pointer to MPT_ADAPTER structure
3388 * @size: total FW bytes
3389 *
3390 * If memory has already been allocated, the same (cached) value
3391 * is returned.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303392 *
3393 * Return 0 if successfull, or non-zero for failure
3394 **/
3395int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
3397{
Prakash, Sathya984621b2008-01-11 14:42:17 +05303398 int rc;
3399
3400 if (ioc->cached_fw) {
3401 rc = 0; /* use already allocated memory */
3402 goto out;
3403 }
3404 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
3406 ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303407 rc = 0;
3408 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05303410 ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
3411 if (!ioc->cached_fw) {
3412 printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
3413 ioc->name);
3414 rc = -1;
3415 } else {
3416 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n",
3417 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
3418 ioc->alloc_total += size;
3419 rc = 0;
3420 }
3421 out:
3422 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423}
Prakash, Sathya984621b2008-01-11 14:42:17 +05303424
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003425/**
3426 * mpt_free_fw_memory - free firmware memory
3427 * @ioc: Pointer to MPT_ADAPTER structure
3428 *
3429 * If alt_img is NULL, delete from ioc structure.
3430 * Else, delete a secondary image in same format.
Prakash, Sathya984621b2008-01-11 14:42:17 +05303431 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432void
3433mpt_free_fw_memory(MPT_ADAPTER *ioc)
3434{
3435 int sz;
3436
Prakash, Sathya984621b2008-01-11 14:42:17 +05303437 if (!ioc->cached_fw)
3438 return;
3439
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 sz = ioc->facts.FWImageSize;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303441 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
3442 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Eric Moore29dd3602007-09-14 18:46:51 -06003443 pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
Prakash, Sathya984621b2008-01-11 14:42:17 +05303444 ioc->alloc_total -= sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445 ioc->cached_fw = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446}
3447
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003449/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
3451 * @ioc: Pointer to MPT_ADAPTER structure
3452 * @sleepFlag: Specifies whether the process can sleep
3453 *
3454 * Returns 0 for success, >0 for handshake failure
3455 * <0 for fw upload failure.
3456 *
3457 * Remark: If bound IOC and a successful FWUpload was performed
3458 * on the bound IOC, the second image is discarded
3459 * and memory is free'd. Both channels must upload to prevent
3460 * IOC from running in degraded mode.
3461 */
3462static int
3463mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
3464{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465 u8 reply[sizeof(FWUploadReply_t)];
3466 FWUpload_t *prequest;
3467 FWUploadReply_t *preply;
3468 FWUploadTCSGE_t *ptcsge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 u32 flagsLength;
3470 int ii, sz, reply_sz;
3471 int cmdStatus;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303472 int request_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473 /* If the image size is 0, we are done.
3474 */
3475 if ((sz = ioc->facts.FWImageSize) == 0)
3476 return 0;
3477
Prakash, Sathya984621b2008-01-11 14:42:17 +05303478 if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
3479 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480
Eric Moore29dd3602007-09-14 18:46:51 -06003481 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
3482 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003483
Eric Moorebc6e0892007-09-29 10:16:28 -06003484 prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
3485 kzalloc(ioc->req_sz, GFP_KERNEL);
3486 if (!prequest) {
3487 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
3488 "while allocating memory \n", ioc->name));
3489 mpt_free_fw_memory(ioc);
3490 return -ENOMEM;
3491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492
Eric Moorebc6e0892007-09-29 10:16:28 -06003493 preply = (FWUploadReply_t *)&reply;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494
3495 reply_sz = sizeof(reply);
3496 memset(preply, 0, reply_sz);
3497
3498 prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM;
3499 prequest->Function = MPI_FUNCTION_FW_UPLOAD;
3500
3501 ptcsge = (FWUploadTCSGE_t *) &prequest->SGL;
3502 ptcsge->DetailsLength = 12;
3503 ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
3504 ptcsge->ImageSize = cpu_to_le32(sz);
Eric Moorebc6e0892007-09-29 10:16:28 -06003505 ptcsge++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303508 ioc->add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
3509 request_size = offsetof(FWUpload_t, SGL) + sizeof(FWUploadTCSGE_t) +
3510 ioc->SGE_size;
3511 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending FW Upload "
3512 " (req @ %p) fw_size=%d mf_request_size=%d\n", ioc->name, prequest,
3513 ioc->facts.FWImageSize, request_size));
Eric Moore29dd3602007-09-14 18:46:51 -06003514 DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303516 ii = mpt_handshake_req_reply_wait(ioc, request_size, (u32 *)prequest,
3517 reply_sz, (u16 *)preply, 65 /*seconds*/, sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518
Eric Moore29dd3602007-09-14 18:46:51 -06003519 dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520
3521 cmdStatus = -EFAULT;
3522 if (ii == 0) {
3523 /* Handshake transfer was complete and successful.
3524 * Check the Reply Frame.
3525 */
3526 int status, transfer_sz;
3527 status = le16_to_cpu(preply->IOCStatus);
3528 if (status == MPI_IOCSTATUS_SUCCESS) {
3529 transfer_sz = le32_to_cpu(preply->ActualImageSize);
3530 if (transfer_sz == sz)
3531 cmdStatus = 0;
3532 }
3533 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303534 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 ioc->name, cmdStatus));
3536
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003537
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538 if (cmdStatus) {
3539
Prakash, Sathya436ace72007-07-24 15:42:08 +05303540 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541 ioc->name));
3542 mpt_free_fw_memory(ioc);
3543 }
Eric Moorebc6e0892007-09-29 10:16:28 -06003544 kfree(prequest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545
3546 return cmdStatus;
3547}
3548
3549/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003550/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551 * mpt_downloadboot - DownloadBoot code
3552 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003553 * @pFwHeader: Pointer to firmware header info
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554 * @sleepFlag: Specifies whether the process can sleep
3555 *
3556 * FwDownloadBoot requires Programmed IO access.
3557 *
3558 * Returns 0 for success
3559 * -1 FW Image size is 0
3560 * -2 No valid cached_fw Pointer
3561 * <0 for fw upload failure.
3562 */
3563static int
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003564mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566 MpiExtImageHeader_t *pExtImage;
3567 u32 fwSize;
3568 u32 diag0val;
3569 int count;
3570 u32 *ptrFw;
3571 u32 diagRwData;
3572 u32 nextImage;
3573 u32 load_addr;
3574 u32 ioc_state=0;
3575
Prakash, Sathya436ace72007-07-24 15:42:08 +05303576 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003577 ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003578
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3580 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3581 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3582 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3583 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3584 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3585
3586 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM));
3587
3588 /* wait 1 msec */
3589 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003590 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 } else {
3592 mdelay (1);
3593 }
3594
3595 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3596 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3597
3598 for (count = 0; count < 30; count ++) {
3599 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3600 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303601 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 ioc->name, count));
3603 break;
3604 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003605 /* wait .1 sec */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003607 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 } else {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003609 mdelay (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 }
3611 }
3612
3613 if ( count == 30 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303614 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003615 "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 ioc->name, diag0val));
3617 return -3;
3618 }
3619
3620 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3621 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3622 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3623 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3624 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3625 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3626
3627 /* Set the DiagRwEn and Disable ARM bits */
3628 CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM));
3629
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 fwSize = (pFwHeader->ImageSize + 3)/4;
3631 ptrFw = (u32 *) pFwHeader;
3632
3633 /* Write the LoadStartAddress to the DiagRw Address Register
3634 * using Programmed IO
3635 */
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003636 if (ioc->errata_flag_1064)
3637 pci_enable_io_access(ioc->pcidev);
3638
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303640 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 ioc->name, pFwHeader->LoadStartAddress));
3642
Prakash, Sathya436ace72007-07-24 15:42:08 +05303643 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644 ioc->name, fwSize*4, ptrFw));
3645 while (fwSize--) {
3646 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3647 }
3648
3649 nextImage = pFwHeader->NextImageHeaderOffset;
3650 while (nextImage) {
3651 pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage);
3652
3653 load_addr = pExtImage->LoadStartAddress;
3654
3655 fwSize = (pExtImage->ImageSize + 3) >> 2;
3656 ptrFw = (u32 *)pExtImage;
3657
Prakash, Sathya436ace72007-07-24 15:42:08 +05303658 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 +02003659 ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
3661
3662 while (fwSize--) {
3663 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
3664 }
3665 nextImage = pExtImage->NextImageHeaderOffset;
3666 }
3667
3668 /* Write the IopResetVectorRegAddr */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303669 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
3671
3672 /* Write the IopResetVectorValue */
Prakash, Sathya436ace72007-07-24 15:42:08 +05303673 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
3675
3676 /* Clear the internal flash bad bit - autoincrementing register,
3677 * so must do two writes.
3678 */
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003679 if (ioc->bus_type == SPI) {
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003680 /*
3681 * 1030 and 1035 H/W errata, workaround to access
3682 * the ClearFlashBadSignatureBit
3683 */
3684 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3685 diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData);
3686 diagRwData |= 0x40000000;
3687 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000);
3688 CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData);
3689
3690 } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ {
3691 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3692 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val |
3693 MPI_DIAG_CLEAR_FLASH_BAD_SIG);
3694
3695 /* wait 1 msec */
3696 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003697 msleep (1);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003698 } else {
3699 mdelay (1);
3700 }
3701 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702
Moore, Eric Dean 3fadc592005-05-11 17:46:52 -06003703 if (ioc->errata_flag_1064)
3704 pci_disable_io_access(ioc->pcidev);
3705
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303707 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003708 "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 ioc->name, diag0val));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003710 diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
Prakash, Sathya436ace72007-07-24 15:42:08 +05303711 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 ioc->name, diag0val));
3713 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
3714
3715 /* Write 0xFF to reset the sequencer */
3716 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3717
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003718 if (ioc->bus_type == SAS) {
3719 ioc_state = mpt_GetIocState(ioc, 0);
3720 if ( (GetIocFacts(ioc, sleepFlag,
3721 MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303722 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003723 ioc->name, ioc_state));
3724 return -EFAULT;
3725 }
3726 }
3727
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728 for (count=0; count<HZ*20; count++) {
3729 if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303730 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3731 "downloadboot successful! (count=%d) IocState=%x\n",
3732 ioc->name, count, ioc_state));
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02003733 if (ioc->bus_type == SAS) {
3734 return 0;
3735 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 if ((SendIocInit(ioc, sleepFlag)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303737 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3738 "downloadboot: SendIocInit failed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 ioc->name));
3740 return -EFAULT;
3741 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303742 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3743 "downloadboot: SendIocInit successful\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744 ioc->name));
3745 return 0;
3746 }
3747 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003748 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749 } else {
3750 mdelay (10);
3751 }
3752 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05303753 ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3754 "downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755 return -EFAULT;
3756}
3757
3758/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003759/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760 * KickStart - Perform hard reset of MPT adapter.
3761 * @ioc: Pointer to MPT_ADAPTER structure
3762 * @force: Force hard reset
3763 * @sleepFlag: Specifies whether the process can sleep
3764 *
3765 * This routine places MPT adapter in diagnostic mode via the
3766 * WriteSequence register, and then performs a hard reset of adapter
3767 * via the Diagnostic register.
3768 *
3769 * Inputs: sleepflag - CAN_SLEEP (non-interrupt thread)
3770 * or NO_SLEEP (interrupt thread, use mdelay)
3771 * force - 1 if doorbell active, board fault state
3772 * board operational, IOC_RECOVERY or
3773 * IOC_BRINGUP and there is an alt_ioc.
3774 * 0 else
3775 *
3776 * Returns:
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003777 * 1 - hard reset, READY
3778 * 0 - no reset due to History bit, READY
3779 * -1 - no reset due to History bit but not READY
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780 * OR reset but failed to come READY
3781 * -2 - no reset, could not enter DIAG mode
3782 * -3 - reset but bad FW bit
3783 */
3784static int
3785KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
3786{
3787 int hard_reset_done = 0;
3788 u32 ioc_state=0;
3789 int cnt,cntdn;
3790
Eric Moore29dd3602007-09-14 18:46:51 -06003791 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
Moore, Eric Deana9b29372005-11-16 18:54:20 -07003792 if (ioc->bus_type == SPI) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 /* Always issue a Msg Unit Reset first. This will clear some
3794 * SCSI bus hang conditions.
3795 */
3796 SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
3797
3798 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003799 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 } else {
3801 mdelay (1000);
3802 }
3803 }
3804
3805 hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
3806 if (hard_reset_done < 0)
3807 return hard_reset_done;
3808
Prakash, Sathya436ace72007-07-24 15:42:08 +05303809 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
Eric Moore29dd3602007-09-14 18:46:51 -06003810 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811
3812 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
3813 for (cnt=0; cnt<cntdn; cnt++) {
3814 ioc_state = mpt_GetIocState(ioc, 1);
3815 if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303816 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 ioc->name, cnt));
3818 return hard_reset_done;
3819 }
3820 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003821 msleep (10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822 } else {
3823 mdelay (10);
3824 }
3825 }
3826
Eric Moore29dd3602007-09-14 18:46:51 -06003827 dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
3828 ioc->name, mpt_GetIocState(ioc, 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 return -1;
3830}
3831
3832/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003833/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834 * mpt_diag_reset - Perform hard reset of the adapter.
3835 * @ioc: Pointer to MPT_ADAPTER structure
3836 * @ignore: Set if to honor and clear to ignore
3837 * the reset history bit
Randy Dunlapd9489fb2006-12-06 20:38:43 -08003838 * @sleepFlag: CAN_SLEEP if called in a non-interrupt thread,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839 * else set to NO_SLEEP (use mdelay instead)
3840 *
3841 * This routine places the adapter in diagnostic mode via the
3842 * WriteSequence register and then performs a hard reset of adapter
3843 * via the Diagnostic register. Adapter should be in ready state
3844 * upon successful completion.
3845 *
3846 * Returns: 1 hard reset successful
3847 * 0 no reset performed because reset history bit set
3848 * -2 enabling diagnostic mode failed
3849 * -3 diagnostic reset failed
3850 */
3851static int
3852mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
3853{
3854 u32 diag0val;
3855 u32 doorbell;
3856 int hard_reset_done = 0;
3857 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858 u32 diag1val = 0;
Prakash, Sathya984621b2008-01-11 14:42:17 +05303859 MpiFwHeader_t *cached_fw; /* Pointer to FW */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003860
Eric Moorecd2c6192007-01-29 09:47:47 -07003861 /* Clear any existing interrupts */
3862 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
3863
Eric Moore87cf8982006-06-27 16:09:26 -06003864 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303865 drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003866 "address=%p\n", ioc->name, __func__,
Eric Moore87cf8982006-06-27 16:09:26 -06003867 &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
3868 CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
3869 if (sleepFlag == CAN_SLEEP)
3870 msleep(1);
3871 else
3872 mdelay(1);
3873
3874 for (count = 0; count < 60; count ++) {
3875 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
3876 doorbell &= MPI_IOC_STATE_MASK;
3877
Prakash, Sathya436ace72007-07-24 15:42:08 +05303878 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Moore87cf8982006-06-27 16:09:26 -06003879 "looking for READY STATE: doorbell=%x"
3880 " count=%d\n",
3881 ioc->name, doorbell, count));
3882 if (doorbell == MPI_IOC_STATE_READY) {
Eric Moorecd2c6192007-01-29 09:47:47 -07003883 return 1;
Eric Moore87cf8982006-06-27 16:09:26 -06003884 }
3885
3886 /* wait 1 sec */
3887 if (sleepFlag == CAN_SLEEP)
3888 msleep(1000);
3889 else
3890 mdelay(1000);
3891 }
3892 return -1;
3893 }
3894
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 /* Use "Diagnostic reset" method! (only thing available!) */
3896 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3897
Prakash, Sathya436ace72007-07-24 15:42:08 +05303898 if (ioc->debug_level & MPT_DEBUG) {
3899 if (ioc->alt_ioc)
3900 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3901 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303903 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904
3905 /* Do the reset if we are told to ignore the reset history
3906 * or if the reset history is 0
3907 */
3908 if (ignore || !(diag0val & MPI_DIAG_RESET_HISTORY)) {
3909 while ((diag0val & MPI_DIAG_DRWE) == 0) {
3910 /* Write magic sequence to WriteSequence register
3911 * Loop until in diagnostic mode
3912 */
3913 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
3914 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
3915 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
3916 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
3917 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
3918 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
3919
3920 /* wait 100 msec */
3921 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05003922 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003923 } else {
3924 mdelay (100);
3925 }
3926
3927 count++;
3928 if (count > 20) {
3929 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
3930 ioc->name, diag0val);
3931 return -2;
3932
3933 }
3934
3935 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
3936
Prakash, Sathya436ace72007-07-24 15:42:08 +05303937 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938 ioc->name, diag0val));
3939 }
3940
Prakash, Sathya436ace72007-07-24 15:42:08 +05303941 if (ioc->debug_level & MPT_DEBUG) {
3942 if (ioc->alt_ioc)
3943 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
3944 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003945 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05303946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947 /*
3948 * Disable the ARM (Bug fix)
3949 *
3950 */
3951 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM);
Christoph Hellwigc6678e02005-08-18 16:24:53 +02003952 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953
3954 /*
3955 * Now hit the reset bit in the Diagnostic register
3956 * (THE BIG HAMMER!) (Clears DRWE bit).
3957 */
3958 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
3959 hard_reset_done = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05303960 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 ioc->name));
3962
3963 /*
3964 * Call each currently registered protocol IOC reset handler
3965 * with pre-reset indication.
3966 * NOTE: If we're doing _IOC_BRINGUP, there can be no
3967 * MptResetHandlers[] registered yet.
3968 */
3969 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303970 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 int r = 0;
3972
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303973 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
3974 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303975 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3976 "Calling IOC pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303977 ioc->name, cb_idx));
3978 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05303980 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3981 "Calling alt-%s pre_reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05303982 ioc->name, ioc->alt_ioc->name, cb_idx));
3983 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 }
3985 }
3986 }
3987 /* FIXME? Examine results here? */
3988 }
3989
Eric Moore0ccdb002006-07-11 17:33:13 -06003990 if (ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303991 cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
Eric Moore0ccdb002006-07-11 17:33:13 -06003992 else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
Prakash, Sathya984621b2008-01-11 14:42:17 +05303993 cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
3994 else
3995 cached_fw = NULL;
3996 if (cached_fw) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997 /* If the DownloadBoot operation fails, the
3998 * IOC will be left unusable. This is a fatal error
3999 * case. _diag_reset will return < 0
4000 */
4001 for (count = 0; count < 30; count ++) {
Prakash, Sathya984621b2008-01-11 14:42:17 +05304002 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003 if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
4004 break;
4005 }
4006
Prakash, Sathya436ace72007-07-24 15:42:08 +05304007 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
Prakash, Sathya984621b2008-01-11 14:42:17 +05304008 ioc->name, diag0val, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 /* wait 1 sec */
4010 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004011 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 } else {
4013 mdelay (1000);
4014 }
4015 }
Prakash, Sathya984621b2008-01-11 14:42:17 +05304016 if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06004017 printk(MYIOC_s_WARN_FMT
4018 "firmware downloadboot failure (%d)!\n", ioc->name, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 }
4020
4021 } else {
4022 /* Wait for FW to reload and for board
4023 * to go to the READY state.
4024 * Maximum wait is 60 seconds.
4025 * If fail, no error will check again
4026 * with calling program.
4027 */
4028 for (count = 0; count < 60; count ++) {
4029 doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
4030 doorbell &= MPI_IOC_STATE_MASK;
4031
4032 if (doorbell == MPI_IOC_STATE_READY) {
4033 break;
4034 }
4035
4036 /* wait 1 sec */
4037 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004038 msleep (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 } else {
4040 mdelay (1000);
4041 }
4042 }
4043 }
4044 }
4045
4046 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304047 if (ioc->debug_level & MPT_DEBUG) {
4048 if (ioc->alt_ioc)
4049 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4050 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
4051 ioc->name, diag0val, diag1val));
4052 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053
4054 /* Clear RESET_HISTORY bit! Place board in the
4055 * diagnostic mode to update the diag register.
4056 */
4057 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4058 count = 0;
4059 while ((diag0val & MPI_DIAG_DRWE) == 0) {
4060 /* Write magic sequence to WriteSequence register
4061 * Loop until in diagnostic mode
4062 */
4063 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
4064 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE);
4065 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE);
4066 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE);
4067 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE);
4068 CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE);
4069
4070 /* wait 100 msec */
4071 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004072 msleep (100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073 } else {
4074 mdelay (100);
4075 }
4076
4077 count++;
4078 if (count > 20) {
4079 printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n",
4080 ioc->name, diag0val);
4081 break;
4082 }
4083 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4084 }
4085 diag0val &= ~MPI_DIAG_RESET_HISTORY;
4086 CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
4087 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4088 if (diag0val & MPI_DIAG_RESET_HISTORY) {
4089 printk(MYIOC_s_WARN_FMT "ResetHistory bit failed to clear!\n",
4090 ioc->name);
4091 }
4092
4093 /* Disable Diagnostic Mode
4094 */
4095 CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFFFFFFFF);
4096
4097 /* Check FW reload status flags.
4098 */
4099 diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
4100 if (diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_RESET_ADAPTER | MPI_DIAG_DISABLE_ARM)) {
4101 printk(MYIOC_s_ERR_FMT "Diagnostic reset FAILED! (%02xh)\n",
4102 ioc->name, diag0val);
4103 return -3;
4104 }
4105
Prakash, Sathya436ace72007-07-24 15:42:08 +05304106 if (ioc->debug_level & MPT_DEBUG) {
4107 if (ioc->alt_ioc)
4108 diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
4109 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110 ioc->name, diag0val, diag1val));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112
4113 /*
4114 * Reset flag that says we've enabled event notification
4115 */
4116 ioc->facts.EventState = 0;
4117
4118 if (ioc->alt_ioc)
4119 ioc->alt_ioc->facts.EventState = 0;
4120
4121 return hard_reset_done;
4122}
4123
4124/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004125/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126 * SendIocReset - Send IOCReset request to MPT adapter.
4127 * @ioc: Pointer to MPT_ADAPTER structure
4128 * @reset_type: reset type, expected values are
4129 * %MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET or %MPI_FUNCTION_IO_UNIT_RESET
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004130 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131 *
4132 * Send IOCReset request to the MPT adapter.
4133 *
4134 * Returns 0 for success, non-zero for failure.
4135 */
4136static int
4137SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
4138{
4139 int r;
4140 u32 state;
4141 int cntdn, count;
4142
Prakash, Sathya436ace72007-07-24 15:42:08 +05304143 drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144 ioc->name, reset_type));
4145 CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
4146 if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4147 return r;
4148
4149 /* FW ACK'd request, wait for READY state
4150 */
4151 count = 0;
4152 cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */
4153
4154 while ((state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) {
4155 cntdn--;
4156 count++;
4157 if (!cntdn) {
4158 if (sleepFlag != CAN_SLEEP)
4159 count *= 10;
4160
Eric Moore29dd3602007-09-14 18:46:51 -06004161 printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
4162 ioc->name, (int)((count+5)/HZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163 return -ETIME;
4164 }
4165
4166 if (sleepFlag == CAN_SLEEP) {
Michael Reedd6be06c2006-05-24 15:07:57 -05004167 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 } else {
4169 mdelay (1); /* 1 msec delay */
4170 }
4171 }
4172
4173 /* TODO!
4174 * Cleanup all event stuff for this IOC; re-issue EventNotification
4175 * request if needed.
4176 */
4177 if (ioc->facts.Function)
4178 ioc->facts.EventState = 0;
4179
4180 return 0;
4181}
4182
4183/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004184/**
4185 * initChainBuffers - Allocate memory for and initialize chain buffers
4186 * @ioc: Pointer to MPT_ADAPTER structure
4187 *
4188 * Allocates memory for and initializes chain buffers,
4189 * chain buffer control arrays and spinlock.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 */
4191static int
4192initChainBuffers(MPT_ADAPTER *ioc)
4193{
4194 u8 *mem;
4195 int sz, ii, num_chain;
4196 int scale, num_sge, numSGE;
4197
4198 /* ReqToChain size must equal the req_depth
4199 * index = req_idx
4200 */
4201 if (ioc->ReqToChain == NULL) {
4202 sz = ioc->req_depth * sizeof(int);
4203 mem = kmalloc(sz, GFP_ATOMIC);
4204 if (mem == NULL)
4205 return -1;
4206
4207 ioc->ReqToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304208 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 ioc->name, mem, sz));
4210 mem = kmalloc(sz, GFP_ATOMIC);
4211 if (mem == NULL)
4212 return -1;
4213
4214 ioc->RequestNB = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304215 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216 ioc->name, mem, sz));
4217 }
4218 for (ii = 0; ii < ioc->req_depth; ii++) {
4219 ioc->ReqToChain[ii] = MPT_HOST_NO_CHAIN;
4220 }
4221
4222 /* ChainToChain size must equal the total number
4223 * of chain buffers to be allocated.
4224 * index = chain_idx
4225 *
4226 * Calculate the number of chain buffers needed(plus 1) per I/O
Michael Opdenacker59c51592007-05-09 08:57:56 +02004227 * then multiply the maximum number of simultaneous cmds
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 *
4229 * num_sge = num sge in request frame + last chain buffer
4230 * scale = num sge per chain buffer if no chain element
4231 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304232 scale = ioc->req_sz / ioc->SGE_size;
4233 if (ioc->sg_addr_size == sizeof(u64))
4234 num_sge = scale + (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235 else
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304236 num_sge = 1 + scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304238 if (ioc->sg_addr_size == sizeof(u64)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239 numSGE = (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304240 (ioc->req_sz - 60) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241 } else {
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304242 numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) +
4243 scale + (ioc->req_sz - 64) / ioc->SGE_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244 }
Prakash, Sathya436ace72007-07-24 15:42:08 +05304245 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246 ioc->name, num_sge, numSGE));
4247
4248 if ( numSGE > MPT_SCSI_SG_DEPTH )
4249 numSGE = MPT_SCSI_SG_DEPTH;
4250
4251 num_chain = 1;
4252 while (numSGE - num_sge > 0) {
4253 num_chain++;
4254 num_sge += (scale - 1);
4255 }
4256 num_chain++;
4257
Prakash, Sathya436ace72007-07-24 15:42:08 +05304258 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259 ioc->name, numSGE, num_sge, num_chain));
4260
Moore, Eric Deana9b29372005-11-16 18:54:20 -07004261 if (ioc->bus_type == SPI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262 num_chain *= MPT_SCSI_CAN_QUEUE;
4263 else
4264 num_chain *= MPT_FC_CAN_QUEUE;
4265
4266 ioc->num_chain = num_chain;
4267
4268 sz = num_chain * sizeof(int);
4269 if (ioc->ChainToChain == NULL) {
4270 mem = kmalloc(sz, GFP_ATOMIC);
4271 if (mem == NULL)
4272 return -1;
4273
4274 ioc->ChainToChain = (int *) mem;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304275 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276 ioc->name, mem, sz));
4277 } else {
4278 mem = (u8 *) ioc->ChainToChain;
4279 }
4280 memset(mem, 0xFF, sz);
4281 return num_chain;
4282}
4283
4284/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004285/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286 * PrimeIocFifos - Initialize IOC request and reply FIFOs.
4287 * @ioc: Pointer to MPT_ADAPTER structure
4288 *
4289 * This routine allocates memory for the MPT reply and request frame
4290 * pools (if necessary), and primes the IOC reply FIFO with
4291 * reply frames.
4292 *
4293 * Returns 0 for success, non-zero for failure.
4294 */
4295static int
4296PrimeIocFifos(MPT_ADAPTER *ioc)
4297{
4298 MPT_FRAME_HDR *mf;
4299 unsigned long flags;
4300 dma_addr_t alloc_dma;
4301 u8 *mem;
4302 int i, reply_sz, sz, total_size, num_chain;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304303 u64 dma_mask;
4304
4305 dma_mask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306
4307 /* Prime reply FIFO... */
4308
4309 if (ioc->reply_frames == NULL) {
4310 if ( (num_chain = initChainBuffers(ioc)) < 0)
4311 return -1;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304312 /*
4313 * 1078 errata workaround for the 36GB limitation
4314 */
4315 if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078 &&
4316 ioc->dma_mask > DMA_35BIT_MASK) {
4317 if (!pci_set_dma_mask(ioc->pcidev, DMA_BIT_MASK(32))
4318 && !pci_set_consistent_dma_mask(ioc->pcidev,
4319 DMA_BIT_MASK(32))) {
4320 dma_mask = DMA_35BIT_MASK;
4321 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4322 "setting 35 bit addressing for "
4323 "Request/Reply/Chain and Sense Buffers\n",
4324 ioc->name));
4325 } else {
4326 /*Reseting DMA mask to 64 bit*/
4327 pci_set_dma_mask(ioc->pcidev,
4328 DMA_BIT_MASK(64));
4329 pci_set_consistent_dma_mask(ioc->pcidev,
4330 DMA_BIT_MASK(64));
4331
4332 printk(MYIOC_s_ERR_FMT
4333 "failed setting 35 bit addressing for "
4334 "Request/Reply/Chain and Sense Buffers\n",
4335 ioc->name);
4336 return -1;
4337 }
4338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339
4340 total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304341 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 ioc->name, ioc->reply_sz, ioc->reply_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304343 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 ioc->name, reply_sz, reply_sz));
4345
4346 sz = (ioc->req_sz * ioc->req_depth);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304347 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348 ioc->name, ioc->req_sz, ioc->req_depth));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304349 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350 ioc->name, sz, sz));
4351 total_size += sz;
4352
4353 sz = num_chain * ioc->req_sz; /* chain buffer pool size */
Prakash, Sathya436ace72007-07-24 15:42:08 +05304354 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 ioc->name, ioc->req_sz, num_chain));
Prakash, Sathya436ace72007-07-24 15:42:08 +05304356 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357 ioc->name, sz, sz, num_chain));
4358
4359 total_size += sz;
4360 mem = pci_alloc_consistent(ioc->pcidev, total_size, &alloc_dma);
4361 if (mem == NULL) {
4362 printk(MYIOC_s_ERR_FMT "Unable to allocate Reply, Request, Chain Buffers!\n",
4363 ioc->name);
4364 goto out_fail;
4365 }
4366
Prakash, Sathya436ace72007-07-24 15:42:08 +05304367 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
4369
4370 memset(mem, 0, total_size);
4371 ioc->alloc_total += total_size;
4372 ioc->alloc = mem;
4373 ioc->alloc_dma = alloc_dma;
4374 ioc->alloc_sz = total_size;
4375 ioc->reply_frames = (MPT_FRAME_HDR *) mem;
4376 ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4377
Prakash, Sathya436ace72007-07-24 15:42:08 +05304378 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004379 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4380
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381 alloc_dma += reply_sz;
4382 mem += reply_sz;
4383
4384 /* Request FIFO - WE manage this! */
4385
4386 ioc->req_frames = (MPT_FRAME_HDR *) mem;
4387 ioc->req_frames_dma = alloc_dma;
4388
Prakash, Sathya436ace72007-07-24 15:42:08 +05304389 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390 ioc->name, mem, (void *)(ulong)alloc_dma));
4391
4392 ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
4393
4394#if defined(CONFIG_MTRR) && 0
4395 /*
4396 * Enable Write Combining MTRR for IOC's memory region.
4397 * (at least as much as we can; "size and base must be
4398 * multiples of 4 kiB"
4399 */
4400 ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
4401 sz,
4402 MTRR_TYPE_WRCOMB, 1);
Prakash, Sathya436ace72007-07-24 15:42:08 +05304403 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 ioc->name, ioc->req_frames_dma, sz));
4405#endif
4406
4407 for (i = 0; i < ioc->req_depth; i++) {
4408 alloc_dma += ioc->req_sz;
4409 mem += ioc->req_sz;
4410 }
4411
4412 ioc->ChainBuffer = mem;
4413 ioc->ChainBufferDMA = alloc_dma;
4414
Prakash, Sathya436ace72007-07-24 15:42:08 +05304415 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416 ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
4417
4418 /* Initialize the free chain Q.
4419 */
4420
4421 INIT_LIST_HEAD(&ioc->FreeChainQ);
4422
4423 /* Post the chain buffers to the FreeChainQ.
4424 */
4425 mem = (u8 *)ioc->ChainBuffer;
4426 for (i=0; i < num_chain; i++) {
4427 mf = (MPT_FRAME_HDR *) mem;
4428 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeChainQ);
4429 mem += ioc->req_sz;
4430 }
4431
4432 /* Initialize Request frames linked list
4433 */
4434 alloc_dma = ioc->req_frames_dma;
4435 mem = (u8 *) ioc->req_frames;
4436
4437 spin_lock_irqsave(&ioc->FreeQlock, flags);
4438 INIT_LIST_HEAD(&ioc->FreeQ);
4439 for (i = 0; i < ioc->req_depth; i++) {
4440 mf = (MPT_FRAME_HDR *) mem;
4441
4442 /* Queue REQUESTs *internally*! */
4443 list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ);
4444
4445 mem += ioc->req_sz;
4446 }
4447 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4448
4449 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4450 ioc->sense_buf_pool =
4451 pci_alloc_consistent(ioc->pcidev, sz, &ioc->sense_buf_pool_dma);
4452 if (ioc->sense_buf_pool == NULL) {
4453 printk(MYIOC_s_ERR_FMT "Unable to allocate Sense Buffers!\n",
4454 ioc->name);
4455 goto out_fail;
4456 }
4457
4458 ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
4459 ioc->alloc_total += sz;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304460 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
4462
4463 }
4464
4465 /* Post Reply frames to FIFO
4466 */
4467 alloc_dma = ioc->alloc_dma;
Prakash, Sathya436ace72007-07-24 15:42:08 +05304468 dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469 ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
4470
4471 for (i = 0; i < ioc->reply_depth; i++) {
4472 /* Write each address to the IOC! */
4473 CHIPREG_WRITE32(&ioc->chip->ReplyFifo, alloc_dma);
4474 alloc_dma += ioc->reply_sz;
4475 }
4476
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304477 if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
4478 ioc->dma_mask) && !pci_set_consistent_dma_mask(ioc->pcidev,
4479 ioc->dma_mask))
4480 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4481 "restoring 64 bit addressing\n", ioc->name));
4482
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 return 0;
4484
4485out_fail:
4486 if (ioc->alloc != NULL) {
4487 sz = ioc->alloc_sz;
4488 pci_free_consistent(ioc->pcidev,
4489 sz,
4490 ioc->alloc, ioc->alloc_dma);
4491 ioc->reply_frames = NULL;
4492 ioc->req_frames = NULL;
4493 ioc->alloc_total -= sz;
4494 }
4495 if (ioc->sense_buf_pool != NULL) {
4496 sz = (ioc->req_depth * MPT_SENSE_BUFFER_ALLOC);
4497 pci_free_consistent(ioc->pcidev,
4498 sz,
4499 ioc->sense_buf_pool, ioc->sense_buf_pool_dma);
4500 ioc->sense_buf_pool = NULL;
4501 }
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304502
4503 if (dma_mask == DMA_35BIT_MASK && !pci_set_dma_mask(ioc->pcidev,
4504 DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(ioc->pcidev,
4505 DMA_BIT_MASK(64)))
4506 d36memprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4507 "restoring 64 bit addressing\n", ioc->name));
4508
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 return -1;
4510}
4511
4512/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4513/**
4514 * mpt_handshake_req_reply_wait - Send MPT request to and receive reply
4515 * from IOC via doorbell handshake method.
4516 * @ioc: Pointer to MPT_ADAPTER structure
4517 * @reqBytes: Size of the request in bytes
4518 * @req: Pointer to MPT request frame
4519 * @replyBytes: Expected size of the reply in bytes
4520 * @u16reply: Pointer to area where reply should be written
4521 * @maxwait: Max wait time for a reply (in seconds)
4522 * @sleepFlag: Specifies whether the process can sleep
4523 *
4524 * NOTES: It is the callers responsibility to byte-swap fields in the
4525 * request which are greater than 1 byte in size. It is also the
4526 * callers responsibility to byte-swap response fields which are
4527 * greater than 1 byte in size.
4528 *
4529 * Returns 0 for success, non-zero for failure.
4530 */
4531static int
4532mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004533 int replyBytes, u16 *u16reply, int maxwait, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534{
4535 MPIDefaultReply_t *mptReply;
4536 int failcnt = 0;
4537 int t;
4538
4539 /*
4540 * Get ready to cache a handshake reply
4541 */
4542 ioc->hs_reply_idx = 0;
4543 mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4544 mptReply->MsgLength = 0;
4545
4546 /*
4547 * Make sure there are no doorbells (WRITE 0 to IntStatus reg),
4548 * then tell IOC that we want to handshake a request of N words.
4549 * (WRITE u32val to Doorbell reg).
4550 */
4551 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4552 CHIPREG_WRITE32(&ioc->chip->Doorbell,
4553 ((MPI_FUNCTION_HANDSHAKE<<MPI_DOORBELL_FUNCTION_SHIFT) |
4554 ((reqBytes/4)<<MPI_DOORBELL_ADD_DWORDS_SHIFT)));
4555
4556 /*
4557 * Wait for IOC's doorbell handshake int
4558 */
4559 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4560 failcnt++;
4561
Prakash, Sathya436ace72007-07-24 15:42:08 +05304562 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4564
4565 /* Read doorbell and check for active bit */
4566 if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
4567 return -1;
4568
4569 /*
4570 * Clear doorbell int (WRITE 0 to IntStatus reg),
4571 * then wait for IOC to ACKnowledge that it's ready for
4572 * our handshake request.
4573 */
4574 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4575 if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4576 failcnt++;
4577
4578 if (!failcnt) {
4579 int ii;
4580 u8 *req_as_bytes = (u8 *) req;
4581
4582 /*
4583 * Stuff request words via doorbell handshake,
4584 * with ACK from IOC for each.
4585 */
4586 for (ii = 0; !failcnt && ii < reqBytes/4; ii++) {
4587 u32 word = ((req_as_bytes[(ii*4) + 0] << 0) |
4588 (req_as_bytes[(ii*4) + 1] << 8) |
4589 (req_as_bytes[(ii*4) + 2] << 16) |
4590 (req_as_bytes[(ii*4) + 3] << 24));
4591
4592 CHIPREG_WRITE32(&ioc->chip->Doorbell, word);
4593 if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
4594 failcnt++;
4595 }
4596
Prakash, Sathya436ace72007-07-24 15:42:08 +05304597 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
Eric Moore29dd3602007-09-14 18:46:51 -06004598 DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599
Prakash, Sathya436ace72007-07-24 15:42:08 +05304600 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601 ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
4602
4603 /*
4604 * Wait for completion of doorbell handshake reply from the IOC
4605 */
4606 if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
4607 failcnt++;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004608
Prakash, Sathya436ace72007-07-24 15:42:08 +05304609 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610 ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
4611
4612 /*
4613 * Copy out the cached reply...
4614 */
4615 for (ii=0; ii < min(replyBytes/2,mptReply->MsgLength*2); ii++)
4616 u16reply[ii] = ioc->hs_reply[ii];
4617 } else {
4618 return -99;
4619 }
4620
4621 return -failcnt;
4622}
4623
4624/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004625/**
4626 * WaitForDoorbellAck - Wait for IOC doorbell handshake acknowledge
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627 * @ioc: Pointer to MPT_ADAPTER structure
4628 * @howlong: How long to wait (in seconds)
4629 * @sleepFlag: Specifies whether the process can sleep
4630 *
4631 * This routine waits (up to ~2 seconds max) for IOC doorbell
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004632 * handshake ACKnowledge, indicated by the IOP_DOORBELL_STATUS
4633 * bit in its IntStatus register being clear.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 *
4635 * Returns a negative value on failure, else wait loop count.
4636 */
4637static int
4638WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4639{
4640 int cntdn;
4641 int count = 0;
4642 u32 intstat=0;
4643
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004644 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645
4646 if (sleepFlag == CAN_SLEEP) {
4647 while (--cntdn) {
Eric Moore0ccdb002006-07-11 17:33:13 -06004648 msleep (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4650 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4651 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652 count++;
4653 }
4654 } else {
4655 while (--cntdn) {
Eric Moorecd2c6192007-01-29 09:47:47 -07004656 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4658 if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
4659 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660 count++;
4661 }
4662 }
4663
4664 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304665 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 ioc->name, count));
4667 return count;
4668 }
4669
4670 printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n",
4671 ioc->name, count, intstat);
4672 return -1;
4673}
4674
4675/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004676/**
4677 * WaitForDoorbellInt - Wait for IOC to set its doorbell interrupt bit
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678 * @ioc: Pointer to MPT_ADAPTER structure
4679 * @howlong: How long to wait (in seconds)
4680 * @sleepFlag: Specifies whether the process can sleep
4681 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004682 * This routine waits (up to ~2 seconds max) for IOC doorbell interrupt
4683 * (MPI_HIS_DOORBELL_INTERRUPT) to be set in the IntStatus register.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684 *
4685 * Returns a negative value on failure, else wait loop count.
4686 */
4687static int
4688WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4689{
4690 int cntdn;
4691 int count = 0;
4692 u32 intstat=0;
4693
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004694 cntdn = 1000 * howlong;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695 if (sleepFlag == CAN_SLEEP) {
4696 while (--cntdn) {
4697 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4698 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4699 break;
Michael Reedd6be06c2006-05-24 15:07:57 -05004700 msleep(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701 count++;
4702 }
4703 } else {
4704 while (--cntdn) {
4705 intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
4706 if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
4707 break;
Eric Moorecd2c6192007-01-29 09:47:47 -07004708 udelay (1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709 count++;
4710 }
4711 }
4712
4713 if (cntdn) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05304714 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715 ioc->name, count, howlong));
4716 return count;
4717 }
4718
4719 printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n",
4720 ioc->name, count, intstat);
4721 return -1;
4722}
4723
4724/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004725/**
4726 * WaitForDoorbellReply - Wait for and capture an IOC handshake reply.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727 * @ioc: Pointer to MPT_ADAPTER structure
4728 * @howlong: How long to wait (in seconds)
4729 * @sleepFlag: Specifies whether the process can sleep
4730 *
4731 * This routine polls the IOC for a handshake reply, 16 bits at a time.
4732 * Reply is cached to IOC private area large enough to hold a maximum
4733 * of 128 bytes of reply data.
4734 *
4735 * Returns a negative value on failure, else size of reply in WORDS.
4736 */
4737static int
4738WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
4739{
4740 int u16cnt = 0;
4741 int failcnt = 0;
4742 int t;
4743 u16 *hs_reply = ioc->hs_reply;
4744 volatile MPIDefaultReply_t *mptReply = (MPIDefaultReply_t *) ioc->hs_reply;
4745 u16 hword;
4746
4747 hs_reply[0] = hs_reply[1] = hs_reply[7] = 0;
4748
4749 /*
4750 * Get first two u16's so we can look at IOC's intended reply MsgLength
4751 */
4752 u16cnt=0;
4753 if ((t = WaitForDoorbellInt(ioc, howlong, sleepFlag)) < 0) {
4754 failcnt++;
4755 } else {
4756 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4757 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4758 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4759 failcnt++;
4760 else {
4761 hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4762 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4763 }
4764 }
4765
Prakash, Sathya436ace72007-07-24 15:42:08 +05304766 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02004767 ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
4769
4770 /*
4771 * If no error (and IOC said MsgLength is > 0), piece together
4772 * reply 16 bits at a time.
4773 */
4774 for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) {
4775 if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4776 failcnt++;
4777 hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF);
4778 /* don't overflow our IOC hs_reply[] buffer! */
Julia Lawalldd7c34e2008-11-09 17:55:27 +01004779 if (u16cnt < ARRAY_SIZE(ioc->hs_reply))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780 hs_reply[u16cnt] = hword;
4781 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4782 }
4783
4784 if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
4785 failcnt++;
4786 CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
4787
4788 if (failcnt) {
4789 printk(MYIOC_s_ERR_FMT "Handshake reply failure!\n",
4790 ioc->name);
4791 return -failcnt;
4792 }
4793#if 0
4794 else if (u16cnt != (2 * mptReply->MsgLength)) {
4795 return -101;
4796 }
4797 else if ((mptReply->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
4798 return -102;
4799 }
4800#endif
4801
Prakash, Sathya436ace72007-07-24 15:42:08 +05304802 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -06004803 DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804
Prakash, Sathya436ace72007-07-24 15:42:08 +05304805 dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 ioc->name, t, u16cnt/2));
4807 return u16cnt/2;
4808}
4809
4810/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004811/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 * GetLanConfigPages - Fetch LANConfig pages.
4813 * @ioc: Pointer to MPT_ADAPTER structure
4814 *
4815 * Return: 0 for success
4816 * -ENOMEM if no memory available
4817 * -EPERM if not allowed due to ISR context
4818 * -EAGAIN if no msg frames currently available
4819 * -EFAULT for non-successful reply or no reply (timeout)
4820 */
4821static int
4822GetLanConfigPages(MPT_ADAPTER *ioc)
4823{
4824 ConfigPageHeader_t hdr;
4825 CONFIGPARMS cfg;
4826 LANPage0_t *ppage0_alloc;
4827 dma_addr_t page0_dma;
4828 LANPage1_t *ppage1_alloc;
4829 dma_addr_t page1_dma;
4830 int rc = 0;
4831 int data_sz;
4832 int copy_sz;
4833
4834 /* Get LAN Page 0 header */
4835 hdr.PageVersion = 0;
4836 hdr.PageLength = 0;
4837 hdr.PageNumber = 0;
4838 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004839 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 cfg.physAddr = -1;
4841 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4842 cfg.dir = 0;
4843 cfg.pageAddr = 0;
4844 cfg.timeout = 0;
4845
4846 if ((rc = mpt_config(ioc, &cfg)) != 0)
4847 return rc;
4848
4849 if (hdr.PageLength > 0) {
4850 data_sz = hdr.PageLength * 4;
4851 ppage0_alloc = (LANPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
4852 rc = -ENOMEM;
4853 if (ppage0_alloc) {
4854 memset((u8 *)ppage0_alloc, 0, data_sz);
4855 cfg.physAddr = page0_dma;
4856 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4857
4858 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4859 /* save the data */
4860 copy_sz = min_t(int, sizeof(LANPage0_t), data_sz);
4861 memcpy(&ioc->lan_cnfg_page0, ppage0_alloc, copy_sz);
4862
4863 }
4864
4865 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
4866
4867 /* FIXME!
4868 * Normalize endianness of structure data,
4869 * by byte-swapping all > 1 byte fields!
4870 */
4871
4872 }
4873
4874 if (rc)
4875 return rc;
4876 }
4877
4878 /* Get LAN Page 1 header */
4879 hdr.PageVersion = 0;
4880 hdr.PageLength = 0;
4881 hdr.PageNumber = 1;
4882 hdr.PageType = MPI_CONFIG_PAGETYPE_LAN;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02004883 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884 cfg.physAddr = -1;
4885 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4886 cfg.dir = 0;
4887 cfg.pageAddr = 0;
4888
4889 if ((rc = mpt_config(ioc, &cfg)) != 0)
4890 return rc;
4891
4892 if (hdr.PageLength == 0)
4893 return 0;
4894
4895 data_sz = hdr.PageLength * 4;
4896 rc = -ENOMEM;
4897 ppage1_alloc = (LANPage1_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page1_dma);
4898 if (ppage1_alloc) {
4899 memset((u8 *)ppage1_alloc, 0, data_sz);
4900 cfg.physAddr = page1_dma;
4901 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4902
4903 if ((rc = mpt_config(ioc, &cfg)) == 0) {
4904 /* save the data */
4905 copy_sz = min_t(int, sizeof(LANPage1_t), data_sz);
4906 memcpy(&ioc->lan_cnfg_page1, ppage1_alloc, copy_sz);
4907 }
4908
4909 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage1_alloc, page1_dma);
4910
4911 /* FIXME!
4912 * Normalize endianness of structure data,
4913 * by byte-swapping all > 1 byte fields!
4914 */
4915
4916 }
4917
4918 return rc;
4919}
4920
4921/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004922/**
4923 * mptbase_sas_persist_operation - Perform operation on SAS Persistent Table
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004924 * @ioc: Pointer to MPT_ADAPTER structure
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004925 * @persist_opcode: see below
4926 *
4927 * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for
4928 * devices not currently present.
4929 * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings
4930 *
4931 * NOTE: Don't use not this function during interrupt time.
4932 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08004933 * Returns 0 for success, non-zero error
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004934 */
4935
4936/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
4937int
4938mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
4939{
4940 SasIoUnitControlRequest_t *sasIoUnitCntrReq;
4941 SasIoUnitControlReply_t *sasIoUnitCntrReply;
4942 MPT_FRAME_HDR *mf = NULL;
4943 MPIHeader_t *mpi_hdr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304944 int ret = 0;
4945 unsigned long timeleft;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004946
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304947 mutex_lock(&ioc->mptbase_cmds.mutex);
4948
4949 /* init the internal cmd struct */
4950 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
4951 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004952
4953 /* insure garbage is not sent to fw */
4954 switch(persist_opcode) {
4955
4956 case MPI_SAS_OP_CLEAR_NOT_PRESENT:
4957 case MPI_SAS_OP_CLEAR_ALL_PERSISTENT:
4958 break;
4959
4960 default:
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304961 ret = -1;
4962 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004963 }
4964
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304965 printk(KERN_DEBUG "%s: persist_opcode=%x\n",
4966 __func__, persist_opcode);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004967
4968 /* Get a MF for this command.
4969 */
4970 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304971 printk(KERN_DEBUG "%s: no msg frames!\n", __func__);
4972 ret = -1;
4973 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004974 }
4975
4976 mpi_hdr = (MPIHeader_t *) mf;
4977 sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf;
4978 memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t));
4979 sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
4980 sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext;
4981 sasIoUnitCntrReq->Operation = persist_opcode;
4982
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004983 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304984 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done, 10*HZ);
4985 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
4986 ret = -ETIME;
4987 printk(KERN_DEBUG "%s: failed\n", __func__);
4988 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
4989 goto out;
4990 if (!timeleft) {
4991 printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n",
4992 ioc->name, __func__);
4993 mpt_HardResetHandler(ioc, CAN_SLEEP);
4994 mpt_free_msg_frame(ioc, mf);
4995 }
4996 goto out;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02004997 }
4998
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05304999 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
5000 ret = -1;
5001 goto out;
5002 }
5003
5004 sasIoUnitCntrReply =
5005 (SasIoUnitControlReply_t *)ioc->mptbase_cmds.reply;
5006 if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
5007 printk(KERN_DEBUG "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
5008 __func__, sasIoUnitCntrReply->IOCStatus,
5009 sasIoUnitCntrReply->IOCLogInfo);
5010 printk(KERN_DEBUG "%s: failed\n", __func__);
5011 ret = -1;
5012 } else
5013 printk(KERN_DEBUG "%s: success\n", __func__);
5014 out:
5015
5016 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
5017 mutex_unlock(&ioc->mptbase_cmds.mutex);
5018 return ret;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02005019}
5020
5021/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Ericece50912006-01-16 18:53:19 -07005022
5023static void
5024mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
5025 MpiEventDataRaid_t * pRaidEventData)
5026{
5027 int volume;
5028 int reason;
5029 int disk;
5030 int status;
5031 int flags;
5032 int state;
5033
5034 volume = pRaidEventData->VolumeID;
5035 reason = pRaidEventData->ReasonCode;
5036 disk = pRaidEventData->PhysDiskNum;
5037 status = le32_to_cpu(pRaidEventData->SettingsStatus);
5038 flags = (status >> 0) & 0xff;
5039 state = (status >> 8) & 0xff;
5040
5041 if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) {
5042 return;
5043 }
5044
5045 if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
5046 reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
5047 (reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005048 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
5049 ioc->name, disk, volume);
Moore, Ericece50912006-01-16 18:53:19 -07005050 } else {
5051 printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
5052 ioc->name, volume);
5053 }
5054
5055 switch(reason) {
5056 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
5057 printk(MYIOC_s_INFO_FMT " volume has been created\n",
5058 ioc->name);
5059 break;
5060
5061 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
5062
5063 printk(MYIOC_s_INFO_FMT " volume has been deleted\n",
5064 ioc->name);
5065 break;
5066
5067 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED:
5068 printk(MYIOC_s_INFO_FMT " volume settings have been changed\n",
5069 ioc->name);
5070 break;
5071
5072 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
5073 printk(MYIOC_s_INFO_FMT " volume is now %s%s%s%s\n",
5074 ioc->name,
5075 state == MPI_RAIDVOL0_STATUS_STATE_OPTIMAL
5076 ? "optimal"
5077 : state == MPI_RAIDVOL0_STATUS_STATE_DEGRADED
5078 ? "degraded"
5079 : state == MPI_RAIDVOL0_STATUS_STATE_FAILED
5080 ? "failed"
5081 : "state unknown",
5082 flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED
5083 ? ", enabled" : "",
5084 flags & MPI_RAIDVOL0_STATUS_FLAG_QUIESCED
5085 ? ", quiesced" : "",
5086 flags & MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS
5087 ? ", resync in progress" : "" );
5088 break;
5089
5090 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED:
5091 printk(MYIOC_s_INFO_FMT " volume membership of PhysDisk %d has changed\n",
5092 ioc->name, disk);
5093 break;
5094
5095 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
5096 printk(MYIOC_s_INFO_FMT " PhysDisk has been created\n",
5097 ioc->name);
5098 break;
5099
5100 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
5101 printk(MYIOC_s_INFO_FMT " PhysDisk has been deleted\n",
5102 ioc->name);
5103 break;
5104
5105 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED:
5106 printk(MYIOC_s_INFO_FMT " PhysDisk settings have been changed\n",
5107 ioc->name);
5108 break;
5109
5110 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
5111 printk(MYIOC_s_INFO_FMT " PhysDisk is now %s%s%s\n",
5112 ioc->name,
5113 state == MPI_PHYSDISK0_STATUS_ONLINE
5114 ? "online"
5115 : state == MPI_PHYSDISK0_STATUS_MISSING
5116 ? "missing"
5117 : state == MPI_PHYSDISK0_STATUS_NOT_COMPATIBLE
5118 ? "not compatible"
5119 : state == MPI_PHYSDISK0_STATUS_FAILED
5120 ? "failed"
5121 : state == MPI_PHYSDISK0_STATUS_INITIALIZING
5122 ? "initializing"
5123 : state == MPI_PHYSDISK0_STATUS_OFFLINE_REQUESTED
5124 ? "offline requested"
5125 : state == MPI_PHYSDISK0_STATUS_FAILED_REQUESTED
5126 ? "failed requested"
5127 : state == MPI_PHYSDISK0_STATUS_OTHER_OFFLINE
5128 ? "offline"
5129 : "state unknown",
5130 flags & MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC
5131 ? ", out of sync" : "",
5132 flags & MPI_PHYSDISK0_STATUS_FLAG_QUIESCED
5133 ? ", quiesced" : "" );
5134 break;
5135
5136 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED:
5137 printk(MYIOC_s_INFO_FMT " Domain Validation needed for PhysDisk %d\n",
5138 ioc->name, disk);
5139 break;
5140
5141 case MPI_EVENT_RAID_RC_SMART_DATA:
5142 printk(MYIOC_s_INFO_FMT " SMART data received, ASC/ASCQ = %02xh/%02xh\n",
5143 ioc->name, pRaidEventData->ASC, pRaidEventData->ASCQ);
5144 break;
5145
5146 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED:
5147 printk(MYIOC_s_INFO_FMT " replacement of PhysDisk %d has started\n",
5148 ioc->name, disk);
5149 break;
5150 }
5151}
5152
5153/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005154/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 * GetIoUnitPage2 - Retrieve BIOS version and boot order information.
5156 * @ioc: Pointer to MPT_ADAPTER structure
5157 *
5158 * Returns: 0 for success
5159 * -ENOMEM if no memory available
5160 * -EPERM if not allowed due to ISR context
5161 * -EAGAIN if no msg frames currently available
5162 * -EFAULT for non-successful reply or no reply (timeout)
5163 */
5164static int
5165GetIoUnitPage2(MPT_ADAPTER *ioc)
5166{
5167 ConfigPageHeader_t hdr;
5168 CONFIGPARMS cfg;
5169 IOUnitPage2_t *ppage_alloc;
5170 dma_addr_t page_dma;
5171 int data_sz;
5172 int rc;
5173
5174 /* Get the page header */
5175 hdr.PageVersion = 0;
5176 hdr.PageLength = 0;
5177 hdr.PageNumber = 2;
5178 hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005179 cfg.cfghdr.hdr = &hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180 cfg.physAddr = -1;
5181 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5182 cfg.dir = 0;
5183 cfg.pageAddr = 0;
5184 cfg.timeout = 0;
5185
5186 if ((rc = mpt_config(ioc, &cfg)) != 0)
5187 return rc;
5188
5189 if (hdr.PageLength == 0)
5190 return 0;
5191
5192 /* Read the config page */
5193 data_sz = hdr.PageLength * 4;
5194 rc = -ENOMEM;
5195 ppage_alloc = (IOUnitPage2_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
5196 if (ppage_alloc) {
5197 memset((u8 *)ppage_alloc, 0, data_sz);
5198 cfg.physAddr = page_dma;
5199 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5200
5201 /* If Good, save data */
5202 if ((rc = mpt_config(ioc, &cfg)) == 0)
5203 ioc->biosVersion = le32_to_cpu(ppage_alloc->BiosVersion);
5204
5205 pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage_alloc, page_dma);
5206 }
5207
5208 return rc;
5209}
5210
5211/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005212/**
5213 * mpt_GetScsiPortSettings - read SCSI Port Page 0 and 2
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214 * @ioc: Pointer to a Adapter Strucutre
5215 * @portnum: IOC port number
5216 *
5217 * Return: -EFAULT if read of config page header fails
5218 * or if no nvram
5219 * If read of SCSI Port Page 0 fails,
5220 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5221 * Adapter settings: async, narrow
5222 * Return 1
5223 * If read of SCSI Port Page 2 fails,
5224 * Adapter settings valid
5225 * NVRAM = MPT_HOST_NVRAM_INVALID (0xFFFFFFFF)
5226 * Return 1
5227 * Else
5228 * Both valid
5229 * Return 0
5230 * CHECK - what type of locking mechanisms should be used????
5231 */
5232static int
5233mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
5234{
5235 u8 *pbuf;
5236 dma_addr_t buf_dma;
5237 CONFIGPARMS cfg;
5238 ConfigPageHeader_t header;
5239 int ii;
5240 int data, rc = 0;
5241
5242 /* Allocate memory
5243 */
5244 if (!ioc->spi_data.nvram) {
5245 int sz;
5246 u8 *mem;
5247 sz = MPT_MAX_SCSI_DEVICES * sizeof(int);
5248 mem = kmalloc(sz, GFP_ATOMIC);
5249 if (mem == NULL)
5250 return -EFAULT;
5251
5252 ioc->spi_data.nvram = (int *) mem;
5253
Prakash, Sathya436ace72007-07-24 15:42:08 +05305254 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255 ioc->name, ioc->spi_data.nvram, sz));
5256 }
5257
5258 /* Invalidate NVRAM information
5259 */
5260 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5261 ioc->spi_data.nvram[ii] = MPT_HOST_NVRAM_INVALID;
5262 }
5263
5264 /* Read SPP0 header, allocate memory, then read page.
5265 */
5266 header.PageVersion = 0;
5267 header.PageLength = 0;
5268 header.PageNumber = 0;
5269 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005270 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271 cfg.physAddr = -1;
5272 cfg.pageAddr = portnum;
5273 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5274 cfg.dir = 0;
5275 cfg.timeout = 0; /* use default */
5276 if (mpt_config(ioc, &cfg) != 0)
5277 return -EFAULT;
5278
5279 if (header.PageLength > 0) {
5280 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5281 if (pbuf) {
5282 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5283 cfg.physAddr = buf_dma;
5284 if (mpt_config(ioc, &cfg) != 0) {
5285 ioc->spi_data.maxBusWidth = MPT_NARROW;
5286 ioc->spi_data.maxSyncOffset = 0;
5287 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5288 ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
5289 rc = 1;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305290 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5291 "Unable to read PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005292 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293 } else {
5294 /* Save the Port Page 0 data
5295 */
5296 SCSIPortPage0_t *pPP0 = (SCSIPortPage0_t *) pbuf;
5297 pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities);
5298 pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface);
5299
5300 if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
5301 ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
Eric Moore29dd3602007-09-14 18:46:51 -06005302 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5303 "noQas due to Capabilities=%x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005304 ioc->name, pPP0->Capabilities));
5305 }
5306 ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
5307 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK;
5308 if (data) {
5309 ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
5310 data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
5311 ioc->spi_data.minSyncFactor = (u8) (data >> 8);
Prakash, Sathya436ace72007-07-24 15:42:08 +05305312 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5313 "PortPage0 minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005314 ioc->name, ioc->spi_data.minSyncFactor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315 } else {
5316 ioc->spi_data.maxSyncOffset = 0;
5317 ioc->spi_data.minSyncFactor = MPT_ASYNC;
5318 }
5319
5320 ioc->spi_data.busType = pPP0->PhysicalInterface & MPI_SCSIPORTPAGE0_PHY_SIGNAL_TYPE_MASK;
5321
5322 /* Update the minSyncFactor based on bus type.
5323 */
5324 if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) ||
5325 (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) {
5326
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005327 if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328 ioc->spi_data.minSyncFactor = MPT_ULTRA;
Prakash, Sathya436ace72007-07-24 15:42:08 +05305329 ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5330 "HVD or SE detected, minSyncFactor=%x\n",
Christoph Hellwigc6678e02005-08-18 16:24:53 +02005331 ioc->name, ioc->spi_data.minSyncFactor));
5332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333 }
5334 }
5335 if (pbuf) {
5336 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5337 }
5338 }
5339 }
5340
5341 /* SCSI Port Page 2 - Read the header then the page.
5342 */
5343 header.PageVersion = 0;
5344 header.PageLength = 0;
5345 header.PageNumber = 2;
5346 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005347 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005348 cfg.physAddr = -1;
5349 cfg.pageAddr = portnum;
5350 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5351 cfg.dir = 0;
5352 if (mpt_config(ioc, &cfg) != 0)
5353 return -EFAULT;
5354
5355 if (header.PageLength > 0) {
5356 /* Allocate memory and read SCSI Port Page 2
5357 */
5358 pbuf = pci_alloc_consistent(ioc->pcidev, header.PageLength * 4, &buf_dma);
5359 if (pbuf) {
5360 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_NVRAM;
5361 cfg.physAddr = buf_dma;
5362 if (mpt_config(ioc, &cfg) != 0) {
5363 /* Nvram data is left with INVALID mark
5364 */
5365 rc = 1;
Eric Moore232f08f2007-08-14 17:28:27 -06005366 } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
5367
5368 /* This is an ATTO adapter, read Page2 accordingly
5369 */
5370 ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
5371 ATTODeviceInfo_t *pdevice = NULL;
5372 u16 ATTOFlags;
5373
5374 /* Save the Port Page 2 data
5375 * (reformat into a 32bit quantity)
5376 */
5377 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5378 pdevice = &pPP2->DeviceSettings[ii];
5379 ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
5380 data = 0;
5381
5382 /* Translate ATTO device flags to LSI format
5383 */
5384 if (ATTOFlags & ATTOFLAG_DISC)
5385 data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
5386 if (ATTOFlags & ATTOFLAG_ID_ENB)
5387 data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
5388 if (ATTOFlags & ATTOFLAG_LUN_ENB)
5389 data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
5390 if (ATTOFlags & ATTOFLAG_TAGGED)
5391 data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
5392 if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
5393 data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
5394
5395 data = (data << 16) | (pdevice->Period << 8) | 10;
5396 ioc->spi_data.nvram[ii] = data;
5397 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398 } else {
5399 SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
5400 MpiDeviceInfo_t *pdevice = NULL;
5401
Moore, Ericd8e925d2006-01-16 18:53:06 -07005402 /*
5403 * Save "Set to Avoid SCSI Bus Resets" flag
5404 */
5405 ioc->spi_data.bus_reset =
5406 (le32_to_cpu(pPP2->PortFlags) &
5407 MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET) ?
5408 0 : 1 ;
5409
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410 /* Save the Port Page 2 data
5411 * (reformat into a 32bit quantity)
5412 */
5413 data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK;
5414 ioc->spi_data.PortFlags = data;
5415 for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
5416 pdevice = &pPP2->DeviceSettings[ii];
5417 data = (le16_to_cpu(pdevice->DeviceFlags) << 16) |
5418 (pdevice->SyncFactor << 8) | pdevice->Timeout;
5419 ioc->spi_data.nvram[ii] = data;
5420 }
5421 }
5422
5423 pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
5424 }
5425 }
5426
5427 /* Update Adapter limits with those from NVRAM
5428 * Comment: Don't need to do this. Target performance
5429 * parameters will never exceed the adapters limits.
5430 */
5431
5432 return rc;
5433}
5434
5435/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005436/**
5437 * mpt_readScsiDevicePageHeaders - save version and length of SDP1
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438 * @ioc: Pointer to a Adapter Strucutre
5439 * @portnum: IOC port number
5440 *
5441 * Return: -EFAULT if read of config page header fails
5442 * or 0 if success.
5443 */
5444static int
5445mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
5446{
5447 CONFIGPARMS cfg;
5448 ConfigPageHeader_t header;
5449
5450 /* Read the SCSI Device Page 1 header
5451 */
5452 header.PageVersion = 0;
5453 header.PageLength = 0;
5454 header.PageNumber = 1;
5455 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005456 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 cfg.physAddr = -1;
5458 cfg.pageAddr = portnum;
5459 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5460 cfg.dir = 0;
5461 cfg.timeout = 0;
5462 if (mpt_config(ioc, &cfg) != 0)
5463 return -EFAULT;
5464
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005465 ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion;
5466 ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467
5468 header.PageVersion = 0;
5469 header.PageLength = 0;
5470 header.PageNumber = 0;
5471 header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
5472 if (mpt_config(ioc, &cfg) != 0)
5473 return -EFAULT;
5474
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005475 ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
5476 ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477
Prakash, Sathya436ace72007-07-24 15:42:08 +05305478 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
5480
Prakash, Sathya436ace72007-07-24 15:42:08 +05305481 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
5483 return 0;
5484}
5485
Eric Mooreb506ade2007-01-29 09:45:37 -07005486/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005487 * mpt_inactive_raid_list_free - This clears this link list.
5488 * @ioc : pointer to per adapter structure
Eric Mooreb506ade2007-01-29 09:45:37 -07005489 **/
5490static void
5491mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
5492{
5493 struct inactive_raid_component_info *component_info, *pNext;
5494
5495 if (list_empty(&ioc->raid_data.inactive_list))
5496 return;
5497
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005498 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005499 list_for_each_entry_safe(component_info, pNext,
5500 &ioc->raid_data.inactive_list, list) {
5501 list_del(&component_info->list);
5502 kfree(component_info);
5503 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005504 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005505}
5506
5507/**
Randy Dunlap1544d672007-02-20 11:17:03 -08005508 * 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 -07005509 *
Randy Dunlap1544d672007-02-20 11:17:03 -08005510 * @ioc : pointer to per adapter structure
5511 * @channel : volume channel
5512 * @id : volume target id
Eric Mooreb506ade2007-01-29 09:45:37 -07005513 **/
5514static void
5515mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
5516{
5517 CONFIGPARMS cfg;
5518 ConfigPageHeader_t hdr;
5519 dma_addr_t dma_handle;
5520 pRaidVolumePage0_t buffer = NULL;
5521 int i;
5522 RaidPhysDiskPage0_t phys_disk;
5523 struct inactive_raid_component_info *component_info;
5524 int handle_inactive_volumes;
5525
5526 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5527 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5528 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
5529 cfg.pageAddr = (channel << 8) + id;
5530 cfg.cfghdr.hdr = &hdr;
5531 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5532
5533 if (mpt_config(ioc, &cfg) != 0)
5534 goto out;
5535
5536 if (!hdr.PageLength)
5537 goto out;
5538
5539 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5540 &dma_handle);
5541
5542 if (!buffer)
5543 goto out;
5544
5545 cfg.physAddr = dma_handle;
5546 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5547
5548 if (mpt_config(ioc, &cfg) != 0)
5549 goto out;
5550
5551 if (!buffer->NumPhysDisks)
5552 goto out;
5553
5554 handle_inactive_volumes =
5555 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
5556 (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
5557 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
5558 buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
5559
5560 if (!handle_inactive_volumes)
5561 goto out;
5562
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005563 mutex_lock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005564 for (i = 0; i < buffer->NumPhysDisks; i++) {
5565 if(mpt_raid_phys_disk_pg0(ioc,
5566 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
5567 continue;
5568
5569 if ((component_info = kmalloc(sizeof (*component_info),
5570 GFP_KERNEL)) == NULL)
5571 continue;
5572
5573 component_info->volumeID = id;
5574 component_info->volumeBus = channel;
5575 component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
5576 component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
5577 component_info->d.PhysDiskID = phys_disk.PhysDiskID;
5578 component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
5579
5580 list_add_tail(&component_info->list,
5581 &ioc->raid_data.inactive_list);
5582 }
Matthias Kaehlckeed5f6062008-03-09 12:16:27 +01005583 mutex_unlock(&ioc->raid_data.inactive_list_mutex);
Eric Mooreb506ade2007-01-29 09:45:37 -07005584
5585 out:
5586 if (buffer)
5587 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5588 dma_handle);
5589}
5590
5591/**
5592 * mpt_raid_phys_disk_pg0 - returns phys disk page zero
5593 * @ioc: Pointer to a Adapter Structure
5594 * @phys_disk_num: io unit unique phys disk num generated by the ioc
5595 * @phys_disk: requested payload data returned
5596 *
5597 * Return:
5598 * 0 on success
5599 * -EFAULT if read of config page header fails or data pointer not NULL
5600 * -ENOMEM if pci_alloc failed
5601 **/
5602int
5603mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
5604{
5605 CONFIGPARMS cfg;
5606 ConfigPageHeader_t hdr;
5607 dma_addr_t dma_handle;
5608 pRaidPhysDiskPage0_t buffer = NULL;
5609 int rc;
5610
5611 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5612 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5613
5614 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
5615 cfg.cfghdr.hdr = &hdr;
5616 cfg.physAddr = -1;
5617 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5618
5619 if (mpt_config(ioc, &cfg) != 0) {
5620 rc = -EFAULT;
5621 goto out;
5622 }
5623
5624 if (!hdr.PageLength) {
5625 rc = -EFAULT;
5626 goto out;
5627 }
5628
5629 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
5630 &dma_handle);
5631
5632 if (!buffer) {
5633 rc = -ENOMEM;
5634 goto out;
5635 }
5636
5637 cfg.physAddr = dma_handle;
5638 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5639 cfg.pageAddr = phys_disk_num;
5640
5641 if (mpt_config(ioc, &cfg) != 0) {
5642 rc = -EFAULT;
5643 goto out;
5644 }
5645
5646 rc = 0;
5647 memcpy(phys_disk, buffer, sizeof(*buffer));
5648 phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
5649
5650 out:
5651
5652 if (buffer)
5653 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
5654 dma_handle);
5655
5656 return rc;
5657}
5658
Linus Torvalds1da177e2005-04-16 15:20:36 -07005659/**
5660 * mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
5661 * @ioc: Pointer to a Adapter Strucutre
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662 *
5663 * Return:
5664 * 0 on success
5665 * -EFAULT if read of config page header fails or data pointer not NULL
5666 * -ENOMEM if pci_alloc failed
Eric Mooreb506ade2007-01-29 09:45:37 -07005667 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005668int
5669mpt_findImVolumes(MPT_ADAPTER *ioc)
5670{
5671 IOCPage2_t *pIoc2;
5672 u8 *mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005673 dma_addr_t ioc2_dma;
5674 CONFIGPARMS cfg;
5675 ConfigPageHeader_t header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676 int rc = 0;
5677 int iocpage2sz;
Eric Mooreb506ade2007-01-29 09:45:37 -07005678 int i;
5679
5680 if (!ioc->ir_firmware)
5681 return 0;
5682
5683 /* Free the old page
5684 */
5685 kfree(ioc->raid_data.pIocPg2);
5686 ioc->raid_data.pIocPg2 = NULL;
5687 mpt_inactive_raid_list_free(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688
5689 /* Read IOCP2 header then the page.
5690 */
5691 header.PageVersion = 0;
5692 header.PageLength = 0;
5693 header.PageNumber = 2;
5694 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005695 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696 cfg.physAddr = -1;
5697 cfg.pageAddr = 0;
5698 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5699 cfg.dir = 0;
5700 cfg.timeout = 0;
5701 if (mpt_config(ioc, &cfg) != 0)
5702 return -EFAULT;
5703
5704 if (header.PageLength == 0)
5705 return -EFAULT;
5706
5707 iocpage2sz = header.PageLength * 4;
5708 pIoc2 = pci_alloc_consistent(ioc->pcidev, iocpage2sz, &ioc2_dma);
5709 if (!pIoc2)
5710 return -ENOMEM;
5711
5712 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5713 cfg.physAddr = ioc2_dma;
5714 if (mpt_config(ioc, &cfg) != 0)
Eric Mooreb506ade2007-01-29 09:45:37 -07005715 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716
Eric Mooreb506ade2007-01-29 09:45:37 -07005717 mem = kmalloc(iocpage2sz, GFP_KERNEL);
5718 if (!mem)
5719 goto out;
5720
Linus Torvalds1da177e2005-04-16 15:20:36 -07005721 memcpy(mem, (u8 *)pIoc2, iocpage2sz);
Eric Mooreb506ade2007-01-29 09:45:37 -07005722 ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005723
Eric Mooreb506ade2007-01-29 09:45:37 -07005724 mpt_read_ioc_pg_3(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005725
Eric Mooreb506ade2007-01-29 09:45:37 -07005726 for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
5727 mpt_inactive_raid_volumes(ioc,
5728 pIoc2->RaidVolume[i].VolumeBus,
5729 pIoc2->RaidVolume[i].VolumeID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730
Eric Mooreb506ade2007-01-29 09:45:37 -07005731 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005732 pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
5733
5734 return rc;
5735}
5736
Moore, Ericc972c702006-03-14 09:14:06 -07005737static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005738mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
5739{
5740 IOCPage3_t *pIoc3;
5741 u8 *mem;
5742 CONFIGPARMS cfg;
5743 ConfigPageHeader_t header;
5744 dma_addr_t ioc3_dma;
5745 int iocpage3sz = 0;
5746
5747 /* Free the old page
5748 */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005749 kfree(ioc->raid_data.pIocPg3);
5750 ioc->raid_data.pIocPg3 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005751
5752 /* There is at least one physical disk.
5753 * Read and save IOC Page 3
5754 */
5755 header.PageVersion = 0;
5756 header.PageLength = 0;
5757 header.PageNumber = 3;
5758 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005759 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005760 cfg.physAddr = -1;
5761 cfg.pageAddr = 0;
5762 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5763 cfg.dir = 0;
5764 cfg.timeout = 0;
5765 if (mpt_config(ioc, &cfg) != 0)
5766 return 0;
5767
5768 if (header.PageLength == 0)
5769 return 0;
5770
5771 /* Read Header good, alloc memory
5772 */
5773 iocpage3sz = header.PageLength * 4;
5774 pIoc3 = pci_alloc_consistent(ioc->pcidev, iocpage3sz, &ioc3_dma);
5775 if (!pIoc3)
5776 return 0;
5777
5778 /* Read the Page and save the data
5779 * into malloc'd memory.
5780 */
5781 cfg.physAddr = ioc3_dma;
5782 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5783 if (mpt_config(ioc, &cfg) == 0) {
Eric Mooreb506ade2007-01-29 09:45:37 -07005784 mem = kmalloc(iocpage3sz, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005785 if (mem) {
5786 memcpy(mem, (u8 *)pIoc3, iocpage3sz);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005787 ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005788 }
5789 }
5790
5791 pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma);
5792
5793 return 0;
5794}
5795
5796static void
5797mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
5798{
5799 IOCPage4_t *pIoc4;
5800 CONFIGPARMS cfg;
5801 ConfigPageHeader_t header;
5802 dma_addr_t ioc4_dma;
5803 int iocpage4sz;
5804
5805 /* Read and save IOC Page 4
5806 */
5807 header.PageVersion = 0;
5808 header.PageLength = 0;
5809 header.PageNumber = 4;
5810 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005811 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005812 cfg.physAddr = -1;
5813 cfg.pageAddr = 0;
5814 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5815 cfg.dir = 0;
5816 cfg.timeout = 0;
5817 if (mpt_config(ioc, &cfg) != 0)
5818 return;
5819
5820 if (header.PageLength == 0)
5821 return;
5822
5823 if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) {
5824 iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */
5825 pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
5826 if (!pIoc4)
5827 return;
Eric Moore0ccdb002006-07-11 17:33:13 -06005828 ioc->alloc_total += iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005829 } else {
5830 ioc4_dma = ioc->spi_data.IocPg4_dma;
5831 iocpage4sz = ioc->spi_data.IocPg4Sz;
5832 }
5833
5834 /* Read the Page into dma memory.
5835 */
5836 cfg.physAddr = ioc4_dma;
5837 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5838 if (mpt_config(ioc, &cfg) == 0) {
5839 ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4;
5840 ioc->spi_data.IocPg4_dma = ioc4_dma;
5841 ioc->spi_data.IocPg4Sz = iocpage4sz;
5842 } else {
5843 pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
5844 ioc->spi_data.pIocPg4 = NULL;
Eric Moore0ccdb002006-07-11 17:33:13 -06005845 ioc->alloc_total -= iocpage4sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005846 }
5847}
5848
5849static void
5850mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
5851{
5852 IOCPage1_t *pIoc1;
5853 CONFIGPARMS cfg;
5854 ConfigPageHeader_t header;
5855 dma_addr_t ioc1_dma;
5856 int iocpage1sz = 0;
5857 u32 tmp;
5858
5859 /* Check the Coalescing Timeout in IOC Page 1
5860 */
5861 header.PageVersion = 0;
5862 header.PageLength = 0;
5863 header.PageNumber = 1;
5864 header.PageType = MPI_CONFIG_PAGETYPE_IOC;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02005865 cfg.cfghdr.hdr = &header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866 cfg.physAddr = -1;
5867 cfg.pageAddr = 0;
5868 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5869 cfg.dir = 0;
5870 cfg.timeout = 0;
5871 if (mpt_config(ioc, &cfg) != 0)
5872 return;
5873
5874 if (header.PageLength == 0)
5875 return;
5876
5877 /* Read Header good, alloc memory
5878 */
5879 iocpage1sz = header.PageLength * 4;
5880 pIoc1 = pci_alloc_consistent(ioc->pcidev, iocpage1sz, &ioc1_dma);
5881 if (!pIoc1)
5882 return;
5883
5884 /* Read the Page and check coalescing timeout
5885 */
5886 cfg.physAddr = ioc1_dma;
5887 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5888 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305889
Linus Torvalds1da177e2005-04-16 15:20:36 -07005890 tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
5891 if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
5892 tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
5893
Prakash, Sathya436ace72007-07-24 15:42:08 +05305894 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005895 ioc->name, tmp));
5896
5897 if (tmp > MPT_COALESCING_TIMEOUT) {
5898 pIoc1->CoalescingTimeout = cpu_to_le32(MPT_COALESCING_TIMEOUT);
5899
5900 /* Write NVRAM and current
5901 */
5902 cfg.dir = 1;
5903 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
5904 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305905 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005906 ioc->name, MPT_COALESCING_TIMEOUT));
5907
5908 cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
5909 if (mpt_config(ioc, &cfg) == 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305910 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5911 "Reset NVRAM Coalescing Timeout to = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005912 ioc->name, MPT_COALESCING_TIMEOUT));
5913 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305914 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5915 "Reset NVRAM Coalescing Timeout Failed\n",
5916 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005917 }
5918
5919 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305920 dprintk(ioc, printk(MYIOC_s_WARN_FMT
5921 "Reset of Current Coalescing Timeout Failed!\n",
5922 ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005923 }
5924 }
5925
5926 } else {
Prakash, Sathya436ace72007-07-24 15:42:08 +05305927 dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005928 }
5929 }
5930
5931 pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma);
5932
5933 return;
5934}
5935
Prakash, Sathyaedb90682007-07-17 14:39:14 +05305936static void
5937mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
5938{
5939 CONFIGPARMS cfg;
5940 ConfigPageHeader_t hdr;
5941 dma_addr_t buf_dma;
5942 ManufacturingPage0_t *pbuf = NULL;
5943
5944 memset(&cfg, 0 , sizeof(CONFIGPARMS));
5945 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
5946
5947 hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
5948 cfg.cfghdr.hdr = &hdr;
5949 cfg.physAddr = -1;
5950 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
5951 cfg.timeout = 10;
5952
5953 if (mpt_config(ioc, &cfg) != 0)
5954 goto out;
5955
5956 if (!cfg.cfghdr.hdr->PageLength)
5957 goto out;
5958
5959 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
5960 pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
5961 if (!pbuf)
5962 goto out;
5963
5964 cfg.physAddr = buf_dma;
5965
5966 if (mpt_config(ioc, &cfg) != 0)
5967 goto out;
5968
5969 memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
5970 memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
5971 memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
5972
5973 out:
5974
5975 if (pbuf)
5976 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
5977}
5978
Linus Torvalds1da177e2005-04-16 15:20:36 -07005979/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08005980/**
5981 * SendEventNotification - Send EventNotification (on or off) request to adapter
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982 * @ioc: Pointer to MPT_ADAPTER structure
5983 * @EvSwitch: Event switch flags
Kashyap, Desaifd761752009-05-29 16:39:06 +05305984 * @sleepFlag: Specifies whether the process can sleep
Linus Torvalds1da177e2005-04-16 15:20:36 -07005985 */
5986static int
Kashyap, Desaifd761752009-05-29 16:39:06 +05305987SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch, int sleepFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988{
Kashyap, Desaifd761752009-05-29 16:39:06 +05305989 EventNotification_t evn;
5990 MPIDefaultReply_t reply_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005991
Kashyap, Desaifd761752009-05-29 16:39:06 +05305992 memset(&evn, 0, sizeof(EventNotification_t));
5993 memset(&reply_buf, 0, sizeof(MPIDefaultReply_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994
Kashyap, Desaifd761752009-05-29 16:39:06 +05305995 evn.Function = MPI_FUNCTION_EVENT_NOTIFICATION;
5996 evn.Switch = EvSwitch;
5997 evn.MsgContext = cpu_to_le32(mpt_base_index << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005998
Kashyap, Desaifd761752009-05-29 16:39:06 +05305999 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6000 "Sending EventNotification (%d) request %p\n",
6001 ioc->name, EvSwitch, &evn));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006002
Kashyap, Desaifd761752009-05-29 16:39:06 +05306003 return mpt_handshake_req_reply_wait(ioc, sizeof(EventNotification_t),
6004 (u32 *)&evn, sizeof(MPIDefaultReply_t), (u16 *)&reply_buf, 30,
6005 sleepFlag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006006}
6007
6008/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6009/**
6010 * SendEventAck - Send EventAck request to MPT adapter.
6011 * @ioc: Pointer to MPT_ADAPTER structure
6012 * @evnp: Pointer to original EventNotification request
6013 */
6014static int
6015SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
6016{
6017 EventAck_t *pAck;
6018
6019 if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306020 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306021 ioc->name, __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006022 return -1;
6023 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006024
Prakash, Sathya436ace72007-07-24 15:42:08 +05306025 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006026
6027 pAck->Function = MPI_FUNCTION_EVENT_ACK;
6028 pAck->ChainOffset = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006029 pAck->Reserved[0] = pAck->Reserved[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006030 pAck->MsgFlags = 0;
Eric Moore4f766dc2006-07-11 17:24:07 -06006031 pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006032 pAck->Event = evnp->Event;
6033 pAck->EventContext = evnp->EventContext;
6034
6035 mpt_put_msg_frame(mpt_base_index, ioc, (MPT_FRAME_HDR *)pAck);
6036
6037 return 0;
6038}
6039
6040/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6041/**
6042 * mpt_config - Generic function to issue config message
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006043 * @ioc: Pointer to an adapter structure
6044 * @pCfg: Pointer to a configuration structure. Struct contains
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045 * action, page address, direction, physical address
6046 * and pointer to a configuration page header
6047 * Page header is updated.
6048 *
6049 * Returns 0 for success
6050 * -EPERM if not allowed due to ISR context
6051 * -EAGAIN if no msg frames currently available
6052 * -EFAULT for non-successful reply or no reply (timeout)
6053 */
6054int
6055mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg)
6056{
6057 Config_t *pReq;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306058 ConfigReply_t *pReply;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006059 ConfigExtendedPageHeader_t *pExtHdr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006060 MPT_FRAME_HDR *mf;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306061 int ii;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006062 int flagsLength;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306063 long timeout;
6064 int ret;
6065 u8 page_type = 0, extend_page;
6066 unsigned long timeleft;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006067 int in_isr;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306068 u8 issue_hard_reset = 0;
6069 u8 retry_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006071 /* Prevent calling wait_event() (below), if caller happens
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072 * to be in ISR context, because that is fatal!
6073 */
6074 in_isr = in_interrupt();
6075 if (in_isr) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306076 dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077 ioc->name));
6078 return -EPERM;
6079 }
6080
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306081 /* don't send if no chance of success */
6082 if (!ioc->active ||
6083 mpt_GetIocState(ioc, 1) != MPI_IOC_STATE_OPERATIONAL) {
6084 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6085 "%s: ioc not operational, %d, %xh\n",
6086 ioc->name, __func__, ioc->active,
6087 mpt_GetIocState(ioc, 0)));
6088 return -EFAULT;
6089 }
6090
6091 retry_config:
6092 mutex_lock(&ioc->mptbase_cmds.mutex);
6093 /* init the internal cmd struct */
6094 memset(ioc->mptbase_cmds.reply, 0 , MPT_DEFAULT_FRAME_SIZE);
6095 INITIALIZE_MGMT_STATUS(ioc->mptbase_cmds.status)
6096
Linus Torvalds1da177e2005-04-16 15:20:36 -07006097 /* Get and Populate a free Frame
6098 */
6099 if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306100 dcprintk(ioc, printk(MYIOC_s_WARN_FMT
6101 "mpt_config: no msg frames!\n", ioc->name));
6102 ret = -EAGAIN;
6103 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006104 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306105
Linus Torvalds1da177e2005-04-16 15:20:36 -07006106 pReq = (Config_t *)mf;
6107 pReq->Action = pCfg->action;
6108 pReq->Reserved = 0;
6109 pReq->ChainOffset = 0;
6110 pReq->Function = MPI_FUNCTION_CONFIG;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006111
6112 /* Assume page type is not extended and clear "reserved" fields. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006113 pReq->ExtPageLength = 0;
6114 pReq->ExtPageType = 0;
6115 pReq->MsgFlags = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006116
Linus Torvalds1da177e2005-04-16 15:20:36 -07006117 for (ii=0; ii < 8; ii++)
6118 pReq->Reserved2[ii] = 0;
6119
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006120 pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion;
6121 pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength;
6122 pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber;
6123 pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
6124
6125 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
6126 pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr;
6127 pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength);
6128 pReq->ExtPageType = pExtHdr->ExtPageType;
6129 pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
6130
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306131 /* Page Length must be treated as a reserved field for the
6132 * extended header.
6133 */
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006134 pReq->Header.PageLength = 0;
6135 }
6136
Linus Torvalds1da177e2005-04-16 15:20:36 -07006137 pReq->PageAddress = cpu_to_le32(pCfg->pageAddr);
6138
6139 /* Add a SGE to the config request.
6140 */
6141 if (pCfg->dir)
6142 flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
6143 else
6144 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
6145
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306146 if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) ==
6147 MPI_CONFIG_PAGETYPE_EXTENDED) {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006148 flagsLength |= pExtHdr->ExtPageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306149 page_type = pReq->ExtPageType;
6150 extend_page = 1;
6151 } else {
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006152 flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306153 page_type = pReq->Header.PageType;
6154 extend_page = 0;
Christoph Hellwig69218ee2005-08-18 16:26:15 +02006155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006156
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306157 dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6158 "Sending Config request type 0x%x, page 0x%x and action %d\n",
6159 ioc->name, page_type, pReq->Header.PageNumber, pReq->Action));
6160
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05306161 ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306162 timeout = (pCfg->timeout < 15) ? HZ*15 : HZ*pCfg->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006163 mpt_put_msg_frame(mpt_base_index, ioc, mf);
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306164 timeleft = wait_for_completion_timeout(&ioc->mptbase_cmds.done,
6165 timeout);
6166 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
6167 ret = -ETIME;
6168 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6169 "Failed Sending Config request type 0x%x, page 0x%x,"
6170 " action %d, status %xh, time left %ld\n\n",
6171 ioc->name, page_type, pReq->Header.PageNumber,
6172 pReq->Action, ioc->mptbase_cmds.status, timeleft));
6173 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
6174 goto out;
6175 if (!timeleft)
6176 issue_hard_reset = 1;
6177 goto out;
6178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006179
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306180 if (!(ioc->mptbase_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
6181 ret = -1;
6182 goto out;
6183 }
6184 pReply = (ConfigReply_t *)ioc->mptbase_cmds.reply;
6185 ret = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
6186 if (ret == MPI_IOCSTATUS_SUCCESS) {
6187 if (extend_page) {
6188 pCfg->cfghdr.ehdr->ExtPageLength =
6189 le16_to_cpu(pReply->ExtPageLength);
6190 pCfg->cfghdr.ehdr->ExtPageType =
6191 pReply->ExtPageType;
6192 }
6193 pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion;
6194 pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength;
6195 pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber;
6196 pCfg->cfghdr.hdr->PageType = pReply->Header.PageType;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006197
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306198 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006199
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306200 if (retry_count)
6201 printk(MYIOC_s_INFO_FMT "Retry completed "
6202 "ret=0x%x timeleft=%ld\n",
6203 ioc->name, ret, timeleft);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006204
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306205 dcprintk(ioc, printk(KERN_DEBUG "IOCStatus=%04xh, IOCLogInfo=%08xh\n",
6206 ret, le32_to_cpu(pReply->IOCLogInfo)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006207
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306208out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006209
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306210 CLEAR_MGMT_STATUS(ioc->mptbase_cmds.status)
6211 mutex_unlock(&ioc->mptbase_cmds.mutex);
6212 if (issue_hard_reset) {
6213 issue_hard_reset = 0;
6214 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
6215 ioc->name, __func__);
6216 mpt_HardResetHandler(ioc, CAN_SLEEP);
6217 mpt_free_msg_frame(ioc, mf);
6218 /* attempt one retry for a timed out command */
6219 if (!retry_count) {
6220 printk(MYIOC_s_INFO_FMT
6221 "Attempting Retry Config request"
6222 " type 0x%x, page 0x%x,"
6223 " action %d\n", ioc->name, page_type,
6224 pCfg->cfghdr.hdr->PageNumber, pCfg->action);
6225 retry_count++;
6226 goto retry_config;
6227 }
6228 }
6229 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006230
Linus Torvalds1da177e2005-04-16 15:20:36 -07006231}
6232
6233/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006234/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006235 * mpt_ioc_reset - Base cleanup for hard reset
6236 * @ioc: Pointer to the adapter structure
6237 * @reset_phase: Indicates pre- or post-reset functionality
6238 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006239 * Remark: Frees resources with internally generated commands.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006240 */
6241static int
6242mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
6243{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306244 switch (reset_phase) {
6245 case MPT_IOC_SETUP_RESET:
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306246 ioc->taskmgmt_quiesce_io = 1;
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306247 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6248 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
6249 break;
6250 case MPT_IOC_PRE_RESET:
6251 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6252 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
6253 break;
6254 case MPT_IOC_POST_RESET:
6255 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
6256 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
6257/* wake up mptbase_cmds */
6258 if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_PENDING) {
6259 ioc->mptbase_cmds.status |=
6260 MPT_MGMT_STATUS_DID_IOCRESET;
6261 complete(&ioc->mptbase_cmds.done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006262 }
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05306263 break;
6264 default:
6265 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006266 }
6267
6268 return 1; /* currently means nothing really */
6269}
6270
6271
6272#ifdef CONFIG_PROC_FS /* { */
6273/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6274/*
6275 * procfs (%MPT_PROCFS_MPTBASEDIR/...) support stuff...
6276 */
6277/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006278/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006279 * procmpt_create - Create %MPT_PROCFS_MPTBASEDIR entries.
6280 *
6281 * Returns 0 for success, non-zero for failure.
6282 */
6283static int
6284procmpt_create(void)
6285{
6286 struct proc_dir_entry *ent;
6287
6288 mpt_proc_root_dir = proc_mkdir(MPT_PROCFS_MPTBASEDIR, NULL);
6289 if (mpt_proc_root_dir == NULL)
6290 return -ENOTDIR;
6291
6292 ent = create_proc_entry("summary", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6293 if (ent)
6294 ent->read_proc = procmpt_summary_read;
6295
6296 ent = create_proc_entry("version", S_IFREG|S_IRUGO, mpt_proc_root_dir);
6297 if (ent)
6298 ent->read_proc = procmpt_version_read;
6299
6300 return 0;
6301}
6302
6303/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006304/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006305 * procmpt_destroy - Tear down %MPT_PROCFS_MPTBASEDIR entries.
6306 *
6307 * Returns 0 for success, non-zero for failure.
6308 */
6309static void
6310procmpt_destroy(void)
6311{
6312 remove_proc_entry("version", mpt_proc_root_dir);
6313 remove_proc_entry("summary", mpt_proc_root_dir);
6314 remove_proc_entry(MPT_PROCFS_MPTBASEDIR, NULL);
6315}
6316
6317/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006318/**
6319 * procmpt_summary_read - Handle read request of a summary file
Linus Torvalds1da177e2005-04-16 15:20:36 -07006320 * @buf: Pointer to area to write information
6321 * @start: Pointer to start pointer
6322 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006323 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006324 * @eof: Pointer to EOF integer
6325 * @data: Pointer
6326 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006327 * Handles read request from /proc/mpt/summary or /proc/mpt/iocN/summary.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006328 * Returns number of characters written to process performing the read.
6329 */
6330static int
6331procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6332{
6333 MPT_ADAPTER *ioc;
6334 char *out = buf;
6335 int len;
6336
6337 if (data) {
6338 int more = 0;
6339
6340 ioc = data;
6341 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6342
6343 out += more;
6344 } else {
6345 list_for_each_entry(ioc, &ioc_list, list) {
6346 int more = 0;
6347
6348 mpt_print_ioc_summary(ioc, out, &more, 0, 1);
6349
6350 out += more;
6351 if ((out-buf) >= request)
6352 break;
6353 }
6354 }
6355
6356 len = out - buf;
6357
6358 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6359}
6360
6361/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006362/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006363 * procmpt_version_read - Handle read request from /proc/mpt/version.
6364 * @buf: Pointer to area to write information
6365 * @start: Pointer to start pointer
6366 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006367 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006368 * @eof: Pointer to EOF integer
6369 * @data: Pointer
6370 *
6371 * Returns number of characters written to process performing the read.
6372 */
6373static int
6374procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6375{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306376 u8 cb_idx;
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006377 int scsi, fc, sas, lan, ctl, targ, dmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006378 char *drvname;
6379 int len;
6380
6381 len = sprintf(buf, "%s-%s\n", "mptlinux", MPT_LINUX_VERSION_COMMON);
6382 len += sprintf(buf+len, " Fusion MPT base driver\n");
6383
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006384 scsi = fc = sas = lan = ctl = targ = dmp = 0;
Eric Moore8d6d83e2007-09-14 18:47:40 -06006385 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006386 drvname = NULL;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306387 if (MptCallbacks[cb_idx]) {
6388 switch (MptDriverClass[cb_idx]) {
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04006389 case MPTSPI_DRIVER:
6390 if (!scsi++) drvname = "SPI host";
6391 break;
6392 case MPTFC_DRIVER:
6393 if (!fc++) drvname = "FC host";
6394 break;
6395 case MPTSAS_DRIVER:
6396 if (!sas++) drvname = "SAS host";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006397 break;
6398 case MPTLAN_DRIVER:
6399 if (!lan++) drvname = "LAN";
6400 break;
6401 case MPTSTM_DRIVER:
6402 if (!targ++) drvname = "SCSI target";
6403 break;
6404 case MPTCTL_DRIVER:
6405 if (!ctl++) drvname = "ioctl";
6406 break;
6407 }
6408
6409 if (drvname)
6410 len += sprintf(buf+len, " Fusion MPT %s driver\n", drvname);
6411 }
6412 }
6413
6414 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6415}
6416
6417/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006418/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07006419 * procmpt_iocinfo_read - Handle read request from /proc/mpt/iocN/info.
6420 * @buf: Pointer to area to write information
6421 * @start: Pointer to start pointer
6422 * @offset: Offset to start writing
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006423 * @request: Amount of read data requested
Linus Torvalds1da177e2005-04-16 15:20:36 -07006424 * @eof: Pointer to EOF integer
6425 * @data: Pointer
6426 *
6427 * Returns number of characters written to process performing the read.
6428 */
6429static int
6430procmpt_iocinfo_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
6431{
6432 MPT_ADAPTER *ioc = data;
6433 int len;
6434 char expVer[32];
6435 int sz;
6436 int p;
6437
6438 mpt_get_fw_exp_ver(expVer, ioc);
6439
6440 len = sprintf(buf, "%s:", ioc->name);
6441 if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)
6442 len += sprintf(buf+len, " (f/w download boot flag set)");
6443// if (ioc->facts.IOCExceptions & MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL)
6444// len += sprintf(buf+len, " CONFIG_CHECKSUM_FAIL!");
6445
6446 len += sprintf(buf+len, "\n ProductID = 0x%04x (%s)\n",
6447 ioc->facts.ProductID,
6448 ioc->prod_name);
6449 len += sprintf(buf+len, " FWVersion = 0x%08x%s", ioc->facts.FWVersion.Word, expVer);
6450 if (ioc->facts.FWImageSize)
6451 len += sprintf(buf+len, " (fw_size=%d)", ioc->facts.FWImageSize);
6452 len += sprintf(buf+len, "\n MsgVersion = 0x%04x\n", ioc->facts.MsgVersion);
6453 len += sprintf(buf+len, " FirstWhoInit = 0x%02x\n", ioc->FirstWhoInit);
6454 len += sprintf(buf+len, " EventState = 0x%02x\n", ioc->facts.EventState);
6455
6456 len += sprintf(buf+len, " CurrentHostMfaHighAddr = 0x%08x\n",
6457 ioc->facts.CurrentHostMfaHighAddr);
6458 len += sprintf(buf+len, " CurrentSenseBufferHighAddr = 0x%08x\n",
6459 ioc->facts.CurrentSenseBufferHighAddr);
6460
6461 len += sprintf(buf+len, " MaxChainDepth = 0x%02x frames\n", ioc->facts.MaxChainDepth);
6462 len += sprintf(buf+len, " MinBlockSize = 0x%02x bytes\n", 4*ioc->facts.BlockSize);
6463
6464 len += sprintf(buf+len, " RequestFrames @ 0x%p (Dma @ 0x%p)\n",
6465 (void *)ioc->req_frames, (void *)(ulong)ioc->req_frames_dma);
6466 /*
6467 * Rounding UP to nearest 4-kB boundary here...
6468 */
6469 sz = (ioc->req_sz * ioc->req_depth) + 128;
6470 sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000;
6471 len += sprintf(buf+len, " {CurReqSz=%d} x {CurReqDepth=%d} = %d bytes ^= 0x%x\n",
6472 ioc->req_sz, ioc->req_depth, ioc->req_sz*ioc->req_depth, sz);
6473 len += sprintf(buf+len, " {MaxReqSz=%d} {MaxReqDepth=%d}\n",
6474 4*ioc->facts.RequestFrameSize,
6475 ioc->facts.GlobalCredits);
6476
6477 len += sprintf(buf+len, " Frames @ 0x%p (Dma @ 0x%p)\n",
6478 (void *)ioc->alloc, (void *)(ulong)ioc->alloc_dma);
6479 sz = (ioc->reply_sz * ioc->reply_depth) + 128;
6480 len += sprintf(buf+len, " {CurRepSz=%d} x {CurRepDepth=%d} = %d bytes ^= 0x%x\n",
6481 ioc->reply_sz, ioc->reply_depth, ioc->reply_sz*ioc->reply_depth, sz);
6482 len += sprintf(buf+len, " {MaxRepSz=%d} {MaxRepDepth=%d}\n",
6483 ioc->facts.CurReplyFrameSize,
6484 ioc->facts.ReplyQueueDepth);
6485
6486 len += sprintf(buf+len, " MaxDevices = %d\n",
6487 (ioc->facts.MaxDevices==0) ? 255 : ioc->facts.MaxDevices);
6488 len += sprintf(buf+len, " MaxBuses = %d\n", ioc->facts.MaxBuses);
6489
6490 /* per-port info */
6491 for (p=0; p < ioc->facts.NumberOfPorts; p++) {
6492 len += sprintf(buf+len, " PortNumber = %d (of %d)\n",
6493 p+1,
6494 ioc->facts.NumberOfPorts);
6495 if (ioc->bus_type == FC) {
6496 if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) {
6497 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6498 len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
6499 a[5], a[4], a[3], a[2], a[1], a[0]);
6500 }
6501 len += sprintf(buf+len, " WWN = %08X%08X:%08X%08X\n",
6502 ioc->fc_port_page0[p].WWNN.High,
6503 ioc->fc_port_page0[p].WWNN.Low,
6504 ioc->fc_port_page0[p].WWPN.High,
6505 ioc->fc_port_page0[p].WWPN.Low);
6506 }
6507 }
6508
6509 MPT_PROC_READ_RETURN(buf,start,offset,request,eof,len);
6510}
6511
6512#endif /* CONFIG_PROC_FS } */
6513
6514/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6515static void
6516mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc)
6517{
6518 buf[0] ='\0';
6519 if ((ioc->facts.FWVersion.Word >> 24) == 0x0E) {
6520 sprintf(buf, " (Exp %02d%02d)",
6521 (ioc->facts.FWVersion.Word >> 16) & 0x00FF, /* Month */
6522 (ioc->facts.FWVersion.Word >> 8) & 0x1F); /* Day */
6523
6524 /* insider hack! */
6525 if ((ioc->facts.FWVersion.Word >> 8) & 0x80)
6526 strcat(buf, " [MDBG]");
6527 }
6528}
6529
6530/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6531/**
6532 * mpt_print_ioc_summary - Write ASCII summary of IOC to a buffer.
6533 * @ioc: Pointer to MPT_ADAPTER structure
6534 * @buffer: Pointer to buffer where IOC summary info should be written
6535 * @size: Pointer to number of bytes we wrote (set by this routine)
6536 * @len: Offset at which to start writing in buffer
6537 * @showlan: Display LAN stuff?
6538 *
6539 * This routine writes (english readable) ASCII text, which represents
6540 * a summary of IOC information, to a buffer.
6541 */
6542void
6543mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int showlan)
6544{
6545 char expVer[32];
6546 int y;
6547
6548 mpt_get_fw_exp_ver(expVer, ioc);
6549
6550 /*
6551 * Shorter summary of attached ioc's...
6552 */
6553 y = sprintf(buffer+len, "%s: %s, %s%08xh%s, Ports=%d, MaxQ=%d",
6554 ioc->name,
6555 ioc->prod_name,
6556 MPT_FW_REV_MAGIC_ID_STRING, /* "FwRev=" or somesuch */
6557 ioc->facts.FWVersion.Word,
6558 expVer,
6559 ioc->facts.NumberOfPorts,
6560 ioc->req_depth);
6561
6562 if (showlan && (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) {
6563 u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
6564 y += sprintf(buffer+len+y, ", LanAddr=%02X:%02X:%02X:%02X:%02X:%02X",
6565 a[5], a[4], a[3], a[2], a[1], a[0]);
6566 }
6567
Linus Torvalds1da177e2005-04-16 15:20:36 -07006568 y += sprintf(buffer+len+y, ", IRQ=%d", ioc->pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006569
6570 if (!ioc->active)
6571 y += sprintf(buffer+len+y, " (disabled)");
6572
6573 y += sprintf(buffer+len+y, "\n");
6574
6575 *size = y;
6576}
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306577/**
6578 * mpt_set_taskmgmt_in_progress_flag - set flags associated with task managment
6579 * @ioc: Pointer to MPT_ADAPTER structure
6580 *
6581 * Returns 0 for SUCCESS or -1 if FAILED.
6582 *
6583 * If -1 is return, then it was not possible to set the flags
6584 **/
6585int
6586mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6587{
6588 unsigned long flags;
6589 int retval;
6590
6591 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6592 if (ioc->ioc_reset_in_progress || ioc->taskmgmt_in_progress ||
6593 (ioc->alt_ioc && ioc->alt_ioc->taskmgmt_in_progress)) {
6594 retval = -1;
6595 goto out;
6596 }
6597 retval = 0;
6598 ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306599 ioc->taskmgmt_quiesce_io = 1;
6600 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306601 ioc->alt_ioc->taskmgmt_in_progress = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306602 ioc->alt_ioc->taskmgmt_quiesce_io = 1;
6603 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306604 out:
6605 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6606 return retval;
6607}
6608EXPORT_SYMBOL(mpt_set_taskmgmt_in_progress_flag);
6609
6610/**
6611 * mpt_clear_taskmgmt_in_progress_flag - clear flags associated with task managment
6612 * @ioc: Pointer to MPT_ADAPTER structure
6613 *
6614 **/
6615void
6616mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc)
6617{
6618 unsigned long flags;
6619
6620 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6621 ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306622 ioc->taskmgmt_quiesce_io = 0;
6623 if (ioc->alt_ioc) {
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306624 ioc->alt_ioc->taskmgmt_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306625 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
6626 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306627 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
6628}
6629EXPORT_SYMBOL(mpt_clear_taskmgmt_in_progress_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006630
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306631
6632/**
6633 * mpt_halt_firmware - Halts the firmware if it is operational and panic
6634 * the kernel
6635 * @ioc: Pointer to MPT_ADAPTER structure
6636 *
6637 **/
6638void
6639mpt_halt_firmware(MPT_ADAPTER *ioc)
6640{
6641 u32 ioc_raw_state;
6642
6643 ioc_raw_state = mpt_GetIocState(ioc, 0);
6644
6645 if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
6646 printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
6647 ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6648 panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
6649 ioc_raw_state & MPI_DOORBELL_DATA_MASK);
6650 } else {
6651 CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
6652 panic("%s: Firmware is halted due to command timeout\n",
6653 ioc->name);
6654 }
6655}
6656EXPORT_SYMBOL(mpt_halt_firmware);
6657
Linus Torvalds1da177e2005-04-16 15:20:36 -07006658/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6659/*
6660 * Reset Handling
6661 */
6662/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
6663/**
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006664 * mpt_HardResetHandler - Generic reset handler
Linus Torvalds1da177e2005-04-16 15:20:36 -07006665 * @ioc: Pointer to MPT_ADAPTER structure
6666 * @sleepFlag: Indicates if sleep or schedule must be called.
6667 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006668 * Issues SCSI Task Management call based on input arg values.
6669 * If TaskMgmt fails, returns associated SCSI request.
6670 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006671 * Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
6672 * or a non-interrupt thread. In the former, must not call schedule().
6673 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08006674 * Note: A return of -1 is a FATAL error case, as it means a
Linus Torvalds1da177e2005-04-16 15:20:36 -07006675 * FW reload/initialization failed.
6676 *
6677 * Returns 0 for SUCCESS or -1 if FAILED.
6678 */
6679int
6680mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
6681{
6682 int rc;
6683 unsigned long flags;
6684
Prakash, Sathya436ace72007-07-24 15:42:08 +05306685 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006686#ifdef MFCNT
6687 printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
6688 printk("MF count 0x%x !\n", ioc->mfcnt);
6689#endif
Kashyap, Desai2f4c7822009-01-06 15:03:37 +05306690 if (mpt_fwfault_debug)
6691 mpt_halt_firmware(ioc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006692
6693 /* Reset the adapter. Prevent more than 1 call to
6694 * mpt_do_ioc_recovery at any instant in time.
6695 */
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306696 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6697 if (ioc->ioc_reset_in_progress) {
6698 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006699 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006700 }
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306701 ioc->ioc_reset_in_progress = 1;
6702 if (ioc->alt_ioc)
6703 ioc->alt_ioc->ioc_reset_in_progress = 1;
6704 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006705
6706 /* FIXME: If do_ioc_recovery fails, repeat....
6707 */
6708
6709 /* The SCSI driver needs to adjust timeouts on all current
6710 * commands prior to the diagnostic reset being issued.
Adrian Bunk80f72282006-06-30 18:27:16 +02006711 * Prevents timeouts occurring during a diagnostic reset...very bad.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006712 * For all other protocol drivers, this is a no-op.
6713 */
6714 {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306715 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006716 int r = 0;
6717
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306718 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
6719 if (MptResetHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306720 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306721 ioc->name, cb_idx));
6722 r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006723 if (ioc->alt_ioc) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05306724 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05306725 ioc->name, ioc->alt_ioc->name, cb_idx));
6726 r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006727 }
6728 }
6729 }
6730 }
6731
6732 if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
Eric Moore29dd3602007-09-14 18:46:51 -06006733 printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006734 }
6735 ioc->reload_fw = 0;
6736 if (ioc->alt_ioc)
6737 ioc->alt_ioc->reload_fw = 0;
6738
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306739 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
6740 ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306741 ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306742 ioc->taskmgmt_in_progress = 0;
6743 if (ioc->alt_ioc) {
6744 ioc->alt_ioc->ioc_reset_in_progress = 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05306745 ioc->alt_ioc->taskmgmt_quiesce_io = 0;
Kashyap, Desai1ba9ab22009-05-29 16:44:48 +05306746 ioc->alt_ioc->taskmgmt_in_progress = 0;
6747 }
6748 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006749
Prakash, Sathya436ace72007-07-24 15:42:08 +05306750 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006751
6752 return rc;
6753}
6754
6755/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006756static void
6757EventDescriptionStr(u8 event, u32 evData0, char *evStr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006758{
Eric Moore509e5e52006-04-26 13:22:37 -06006759 char *ds = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006760
6761 switch(event) {
6762 case MPI_EVENT_NONE:
6763 ds = "None";
6764 break;
6765 case MPI_EVENT_LOG_DATA:
6766 ds = "Log Data";
6767 break;
6768 case MPI_EVENT_STATE_CHANGE:
6769 ds = "State Change";
6770 break;
6771 case MPI_EVENT_UNIT_ATTENTION:
6772 ds = "Unit Attention";
6773 break;
6774 case MPI_EVENT_IOC_BUS_RESET:
6775 ds = "IOC Bus Reset";
6776 break;
6777 case MPI_EVENT_EXT_BUS_RESET:
6778 ds = "External Bus Reset";
6779 break;
6780 case MPI_EVENT_RESCAN:
6781 ds = "Bus Rescan Event";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006782 break;
6783 case MPI_EVENT_LINK_STATUS_CHANGE:
6784 if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
6785 ds = "Link Status(FAILURE) Change";
6786 else
6787 ds = "Link Status(ACTIVE) Change";
6788 break;
6789 case MPI_EVENT_LOOP_STATE_CHANGE:
6790 if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LIP)
6791 ds = "Loop State(LIP) Change";
6792 else if (evData0 == MPI_EVENT_LOOP_STATE_CHANGE_LPE)
Eric Moore509e5e52006-04-26 13:22:37 -06006793 ds = "Loop State(LPE) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006794 else
Eric Moore509e5e52006-04-26 13:22:37 -06006795 ds = "Loop State(LPB) Change"; /* ??? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006796 break;
6797 case MPI_EVENT_LOGOUT:
6798 ds = "Logout";
6799 break;
6800 case MPI_EVENT_EVENT_CHANGE:
6801 if (evData0)
Eric Moore4f766dc2006-07-11 17:24:07 -06006802 ds = "Events ON";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006803 else
Eric Moore4f766dc2006-07-11 17:24:07 -06006804 ds = "Events OFF";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006805 break;
6806 case MPI_EVENT_INTEGRATED_RAID:
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006807 {
6808 u8 ReasonCode = (u8)(evData0 >> 16);
6809 switch (ReasonCode) {
6810 case MPI_EVENT_RAID_RC_VOLUME_CREATED :
6811 ds = "Integrated Raid: Volume Created";
6812 break;
6813 case MPI_EVENT_RAID_RC_VOLUME_DELETED :
6814 ds = "Integrated Raid: Volume Deleted";
6815 break;
6816 case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED :
6817 ds = "Integrated Raid: Volume Settings Changed";
6818 break;
6819 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED :
6820 ds = "Integrated Raid: Volume Status Changed";
6821 break;
6822 case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED :
6823 ds = "Integrated Raid: Volume Physdisk Changed";
6824 break;
6825 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED :
6826 ds = "Integrated Raid: Physdisk Created";
6827 break;
6828 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED :
6829 ds = "Integrated Raid: Physdisk Deleted";
6830 break;
6831 case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED :
6832 ds = "Integrated Raid: Physdisk Settings Changed";
6833 break;
6834 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED :
6835 ds = "Integrated Raid: Physdisk Status Changed";
6836 break;
6837 case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED :
6838 ds = "Integrated Raid: Domain Validation Needed";
6839 break;
6840 case MPI_EVENT_RAID_RC_SMART_DATA :
6841 ds = "Integrated Raid; Smart Data";
6842 break;
6843 case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED :
6844 ds = "Integrated Raid: Replace Action Started";
6845 break;
6846 default:
6847 ds = "Integrated Raid";
Linus Torvalds1da177e2005-04-16 15:20:36 -07006848 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006849 }
6850 break;
6851 }
6852 case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE:
6853 ds = "SCSI Device Status Change";
6854 break;
6855 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
6856 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006857 u8 id = (u8)(evData0);
Eric Moorec6c727a2007-01-29 09:44:54 -07006858 u8 channel = (u8)(evData0 >> 8);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006859 u8 ReasonCode = (u8)(evData0 >> 16);
6860 switch (ReasonCode) {
6861 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006862 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006863 "SAS Device Status Change: Added: "
6864 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006865 break;
6866 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Moore509e5e52006-04-26 13:22:37 -06006867 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006868 "SAS Device Status Change: Deleted: "
6869 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006870 break;
6871 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Moore509e5e52006-04-26 13:22:37 -06006872 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006873 "SAS Device Status Change: SMART Data: "
6874 "id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006875 break;
6876 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Eric Moore509e5e52006-04-26 13:22:37 -06006877 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006878 "SAS Device Status Change: No Persistancy: "
6879 "id=%d channel=%d", id, channel);
6880 break;
6881 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
6882 snprintf(evStr, EVENT_DESCR_STR_SZ,
6883 "SAS Device Status Change: Unsupported Device "
6884 "Discovered : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006885 break;
6886 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
6887 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006888 "SAS Device Status Change: Internal Device "
6889 "Reset : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006890 break;
6891 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
6892 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006893 "SAS Device Status Change: Internal Task "
6894 "Abort : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006895 break;
6896 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
6897 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006898 "SAS Device Status Change: Internal Abort "
6899 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006900 break;
6901 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
6902 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006903 "SAS Device Status Change: Internal Clear "
6904 "Task Set : id=%d channel=%d", id, channel);
Eric Moore4f766dc2006-07-11 17:24:07 -06006905 break;
6906 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
6907 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006908 "SAS Device Status Change: Internal Query "
6909 "Task : id=%d channel=%d", id, channel);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006910 break;
6911 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006912 snprintf(evStr, EVENT_DESCR_STR_SZ,
Eric Moorec6c727a2007-01-29 09:44:54 -07006913 "SAS Device Status Change: Unknown: "
6914 "id=%d channel=%d", id, channel);
Eric Moore509e5e52006-04-26 13:22:37 -06006915 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006916 }
6917 break;
6918 }
6919 case MPI_EVENT_ON_BUS_TIMER_EXPIRED:
6920 ds = "Bus Timer Expired";
6921 break;
6922 case MPI_EVENT_QUEUE_FULL:
Eric Moorec6c727a2007-01-29 09:44:54 -07006923 {
6924 u16 curr_depth = (u16)(evData0 >> 16);
6925 u8 channel = (u8)(evData0 >> 8);
6926 u8 id = (u8)(evData0);
6927
6928 snprintf(evStr, EVENT_DESCR_STR_SZ,
6929 "Queue Full: channel=%d id=%d depth=%d",
6930 channel, id, curr_depth);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006931 break;
Eric Moorec6c727a2007-01-29 09:44:54 -07006932 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006933 case MPI_EVENT_SAS_SES:
6934 ds = "SAS SES Event";
6935 break;
6936 case MPI_EVENT_PERSISTENT_TABLE_FULL:
6937 ds = "Persistent Table Full";
6938 break;
6939 case MPI_EVENT_SAS_PHY_LINK_STATUS:
Moore, Eric3a892be2006-03-14 09:14:03 -07006940 {
Moore, Eric3a892be2006-03-14 09:14:03 -07006941 u8 LinkRates = (u8)(evData0 >> 8);
6942 u8 PhyNumber = (u8)(evData0);
6943 LinkRates = (LinkRates & MPI_EVENT_SAS_PLS_LR_CURRENT_MASK) >>
6944 MPI_EVENT_SAS_PLS_LR_CURRENT_SHIFT;
6945 switch (LinkRates) {
6946 case MPI_EVENT_SAS_PLS_LR_RATE_UNKNOWN:
Eric Moore509e5e52006-04-26 13:22:37 -06006947 snprintf(evStr, EVENT_DESCR_STR_SZ,
6948 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006949 " Rate Unknown",PhyNumber);
6950 break;
6951 case MPI_EVENT_SAS_PLS_LR_RATE_PHY_DISABLED:
Eric Moore509e5e52006-04-26 13:22:37 -06006952 snprintf(evStr, EVENT_DESCR_STR_SZ,
6953 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006954 " Phy Disabled",PhyNumber);
6955 break;
6956 case MPI_EVENT_SAS_PLS_LR_RATE_FAILED_SPEED_NEGOTIATION:
Eric Moore509e5e52006-04-26 13:22:37 -06006957 snprintf(evStr, EVENT_DESCR_STR_SZ,
6958 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006959 " Failed Speed Nego",PhyNumber);
6960 break;
6961 case MPI_EVENT_SAS_PLS_LR_RATE_SATA_OOB_COMPLETE:
Eric Moore509e5e52006-04-26 13:22:37 -06006962 snprintf(evStr, EVENT_DESCR_STR_SZ,
6963 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006964 " Sata OOB Completed",PhyNumber);
6965 break;
6966 case MPI_EVENT_SAS_PLS_LR_RATE_1_5:
Eric Moore509e5e52006-04-26 13:22:37 -06006967 snprintf(evStr, EVENT_DESCR_STR_SZ,
6968 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006969 " Rate 1.5 Gbps",PhyNumber);
6970 break;
6971 case MPI_EVENT_SAS_PLS_LR_RATE_3_0:
Eric Moore509e5e52006-04-26 13:22:37 -06006972 snprintf(evStr, EVENT_DESCR_STR_SZ,
6973 "SAS PHY Link Status: Phy=%d:"
Moore, Eric3a892be2006-03-14 09:14:03 -07006974 " Rate 3.0 Gpbs",PhyNumber);
6975 break;
6976 default:
Eric Moore509e5e52006-04-26 13:22:37 -06006977 snprintf(evStr, EVENT_DESCR_STR_SZ,
6978 "SAS PHY Link Status: Phy=%d", PhyNumber);
Moore, Eric3a892be2006-03-14 09:14:03 -07006979 break;
6980 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006981 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006982 }
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02006983 case MPI_EVENT_SAS_DISCOVERY_ERROR:
6984 ds = "SAS Discovery Error";
6985 break;
Moore, Eric3a892be2006-03-14 09:14:03 -07006986 case MPI_EVENT_IR_RESYNC_UPDATE:
6987 {
6988 u8 resync_complete = (u8)(evData0 >> 16);
Eric Moore509e5e52006-04-26 13:22:37 -06006989 snprintf(evStr, EVENT_DESCR_STR_SZ,
6990 "IR Resync Update: Complete = %d:",resync_complete);
Moore, Eric3a892be2006-03-14 09:14:03 -07006991 break;
6992 }
6993 case MPI_EVENT_IR2:
6994 {
6995 u8 ReasonCode = (u8)(evData0 >> 16);
6996 switch (ReasonCode) {
6997 case MPI_EVENT_IR2_RC_LD_STATE_CHANGED:
6998 ds = "IR2: LD State Changed";
6999 break;
7000 case MPI_EVENT_IR2_RC_PD_STATE_CHANGED:
7001 ds = "IR2: PD State Changed";
7002 break;
7003 case MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL:
7004 ds = "IR2: Bad Block Table Full";
7005 break;
7006 case MPI_EVENT_IR2_RC_PD_INSERTED:
7007 ds = "IR2: PD Inserted";
7008 break;
7009 case MPI_EVENT_IR2_RC_PD_REMOVED:
7010 ds = "IR2: PD Removed";
7011 break;
7012 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
7013 ds = "IR2: Foreign CFG Detected";
7014 break;
7015 case MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR:
7016 ds = "IR2: Rebuild Medium Error";
7017 break;
7018 default:
7019 ds = "IR2";
7020 break;
7021 }
7022 break;
7023 }
7024 case MPI_EVENT_SAS_DISCOVERY:
7025 {
7026 if (evData0)
7027 ds = "SAS Discovery: Start";
7028 else
7029 ds = "SAS Discovery: Stop";
7030 break;
7031 }
7032 case MPI_EVENT_LOG_ENTRY_ADDED:
7033 ds = "SAS Log Entry Added";
7034 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007035
Eric Moorec6c727a2007-01-29 09:44:54 -07007036 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
7037 {
7038 u8 phy_num = (u8)(evData0);
7039 u8 port_num = (u8)(evData0 >> 8);
7040 u8 port_width = (u8)(evData0 >> 16);
7041 u8 primative = (u8)(evData0 >> 24);
7042 snprintf(evStr, EVENT_DESCR_STR_SZ,
7043 "SAS Broadcase Primative: phy=%d port=%d "
7044 "width=%d primative=0x%02x",
7045 phy_num, port_num, port_width, primative);
7046 break;
7047 }
7048
7049 case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
7050 {
7051 u8 reason = (u8)(evData0);
7052 u8 port_num = (u8)(evData0 >> 8);
7053 u16 handle = le16_to_cpu(evData0 >> 16);
7054
7055 snprintf(evStr, EVENT_DESCR_STR_SZ,
7056 "SAS Initiator Device Status Change: reason=0x%02x "
7057 "port=%d handle=0x%04x",
7058 reason, port_num, handle);
7059 break;
7060 }
7061
7062 case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
7063 {
7064 u8 max_init = (u8)(evData0);
7065 u8 current_init = (u8)(evData0 >> 8);
7066
7067 snprintf(evStr, EVENT_DESCR_STR_SZ,
7068 "SAS Initiator Device Table Overflow: max initiators=%02d "
7069 "current initators=%02d",
7070 max_init, current_init);
7071 break;
7072 }
7073 case MPI_EVENT_SAS_SMP_ERROR:
7074 {
7075 u8 status = (u8)(evData0);
7076 u8 port_num = (u8)(evData0 >> 8);
7077 u8 result = (u8)(evData0 >> 16);
7078
7079 if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
7080 snprintf(evStr, EVENT_DESCR_STR_SZ,
7081 "SAS SMP Error: port=%d result=0x%02x",
7082 port_num, result);
7083 else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
7084 snprintf(evStr, EVENT_DESCR_STR_SZ,
7085 "SAS SMP Error: port=%d : CRC Error",
7086 port_num);
7087 else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
7088 snprintf(evStr, EVENT_DESCR_STR_SZ,
7089 "SAS SMP Error: port=%d : Timeout",
7090 port_num);
7091 else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
7092 snprintf(evStr, EVENT_DESCR_STR_SZ,
7093 "SAS SMP Error: port=%d : No Destination",
7094 port_num);
7095 else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
7096 snprintf(evStr, EVENT_DESCR_STR_SZ,
7097 "SAS SMP Error: port=%d : Bad Destination",
7098 port_num);
7099 else
7100 snprintf(evStr, EVENT_DESCR_STR_SZ,
7101 "SAS SMP Error: port=%d : status=0x%02x",
7102 port_num, status);
7103 break;
7104 }
7105
Linus Torvalds1da177e2005-04-16 15:20:36 -07007106 /*
7107 * MPT base "custom" events may be added here...
7108 */
7109 default:
7110 ds = "Unknown";
7111 break;
7112 }
Eric Moore509e5e52006-04-26 13:22:37 -06007113 if (ds)
7114 strncpy(evStr, ds, EVENT_DESCR_STR_SZ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007115}
7116
7117/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007118/**
7119 * ProcessEventNotification - Route EventNotificationReply to all event handlers
Linus Torvalds1da177e2005-04-16 15:20:36 -07007120 * @ioc: Pointer to MPT_ADAPTER structure
7121 * @pEventReply: Pointer to EventNotification reply frame
7122 * @evHandlers: Pointer to integer, number of event handlers
7123 *
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007124 * Routes a received EventNotificationReply to all currently registered
7125 * event handlers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007126 * Returns sum of event handlers return values.
7127 */
7128static int
7129ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply, int *evHandlers)
7130{
7131 u16 evDataLen;
7132 u32 evData0 = 0;
7133// u32 evCtx;
7134 int ii;
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307135 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007136 int r = 0;
7137 int handlers = 0;
Eric Moore509e5e52006-04-26 13:22:37 -06007138 char evStr[EVENT_DESCR_STR_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007139 u8 event;
7140
7141 /*
7142 * Do platform normalization of values
7143 */
7144 event = le32_to_cpu(pEventReply->Event) & 0xFF;
7145// evCtx = le32_to_cpu(pEventReply->EventContext);
7146 evDataLen = le16_to_cpu(pEventReply->EventDataLength);
7147 if (evDataLen) {
7148 evData0 = le32_to_cpu(pEventReply->Data[0]);
7149 }
7150
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007151 EventDescriptionStr(event, evData0, evStr);
Prakash, Sathya436ace72007-07-24 15:42:08 +05307152 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007153 ioc->name,
Moore, Eric3a892be2006-03-14 09:14:03 -07007154 event,
7155 evStr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007156
Prakash, Sathya436ace72007-07-24 15:42:08 +05307157#ifdef CONFIG_FUSION_LOGGING
Eric Moore29dd3602007-09-14 18:46:51 -06007158 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
7159 ": Event data:\n", ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007160 for (ii = 0; ii < evDataLen; ii++)
Prakash, Sathya436ace72007-07-24 15:42:08 +05307161 devtverboseprintk(ioc, printk(" %08x",
7162 le32_to_cpu(pEventReply->Data[ii])));
Eric Moore29dd3602007-09-14 18:46:51 -06007163 devtverboseprintk(ioc, printk("\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007164#endif
7165
7166 /*
7167 * Do general / base driver event processing
7168 */
7169 switch(event) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007170 case MPI_EVENT_EVENT_CHANGE: /* 0A */
7171 if (evDataLen) {
7172 u8 evState = evData0 & 0xFF;
7173
7174 /* CHECKME! What if evState unexpectedly says OFF (0)? */
7175
7176 /* Update EventState field in cached IocFacts */
7177 if (ioc->facts.Function) {
7178 ioc->facts.EventState = evState;
7179 }
7180 }
7181 break;
Moore, Ericece50912006-01-16 18:53:19 -07007182 case MPI_EVENT_INTEGRATED_RAID:
7183 mptbase_raid_process_event_data(ioc,
7184 (MpiEventDataRaid_t *)pEventReply->Data);
7185 break;
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007186 default:
7187 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007188 }
7189
7190 /*
7191 * Should this event be logged? Events are written sequentially.
7192 * When buffer is full, start again at the top.
7193 */
7194 if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
7195 int idx;
7196
Moore, Eric5b5ef4f2006-02-02 17:19:40 -07007197 idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007198
7199 ioc->events[idx].event = event;
7200 ioc->events[idx].eventContext = ioc->eventContext;
7201
7202 for (ii = 0; ii < 2; ii++) {
7203 if (ii < evDataLen)
7204 ioc->events[idx].data[ii] = le32_to_cpu(pEventReply->Data[ii]);
7205 else
7206 ioc->events[idx].data[ii] = 0;
7207 }
7208
7209 ioc->eventContext++;
7210 }
7211
7212
7213 /*
7214 * Call each currently registered protocol event handler.
7215 */
Eric Moore8d6d83e2007-09-14 18:47:40 -06007216 for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307217 if (MptEvHandlers[cb_idx]) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307218 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307219 ioc->name, cb_idx));
7220 r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007221 handlers++;
7222 }
7223 }
7224 /* FIXME? Examine results here? */
7225
7226 /*
7227 * If needed, send (a single) EventAck.
7228 */
7229 if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307230 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007231 "EventAck required\n",ioc->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007232 if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
Prakash, Sathya436ace72007-07-24 15:42:08 +05307233 devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07007234 ioc->name, ii));
7235 }
7236 }
7237
7238 *evHandlers = handlers;
7239 return r;
7240}
7241
7242/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007243/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007244 * mpt_fc_log_info - Log information returned from Fibre Channel IOC.
7245 * @ioc: Pointer to MPT_ADAPTER structure
7246 * @log_info: U32 LogInfo reply word from the IOC
7247 *
Eric Moore4f766dc2006-07-11 17:24:07 -06007248 * Refer to lsi/mpi_log_fc.h.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007249 */
7250static void
7251mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
7252{
Eric Moore7c431e52007-06-13 16:34:36 -06007253 char *desc = "unknown";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007254
Eric Moore7c431e52007-06-13 16:34:36 -06007255 switch (log_info & 0xFF000000) {
7256 case MPI_IOCLOGINFO_FC_INIT_BASE:
7257 desc = "FCP Initiator";
7258 break;
7259 case MPI_IOCLOGINFO_FC_TARGET_BASE:
7260 desc = "FCP Target";
7261 break;
7262 case MPI_IOCLOGINFO_FC_LAN_BASE:
7263 desc = "LAN";
7264 break;
7265 case MPI_IOCLOGINFO_FC_MSG_BASE:
7266 desc = "MPI Message Layer";
7267 break;
7268 case MPI_IOCLOGINFO_FC_LINK_BASE:
7269 desc = "FC Link";
7270 break;
7271 case MPI_IOCLOGINFO_FC_CTX_BASE:
7272 desc = "Context Manager";
7273 break;
7274 case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
7275 desc = "Invalid Field Offset";
7276 break;
7277 case MPI_IOCLOGINFO_FC_STATE_CHANGE:
7278 desc = "State Change Info";
7279 break;
7280 }
7281
7282 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
7283 ioc->name, log_info, desc, (log_info & 0xFFFFFF));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007284}
7285
7286/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007287/**
Moore, Eric335a9412006-01-17 17:06:23 -07007288 * mpt_spi_log_info - Log information returned from SCSI Parallel IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007289 * @ioc: Pointer to MPT_ADAPTER structure
Linus Torvalds1da177e2005-04-16 15:20:36 -07007290 * @log_info: U32 LogInfo word from the IOC
7291 *
7292 * Refer to lsi/sp_log.h.
7293 */
7294static void
Moore, Eric335a9412006-01-17 17:06:23 -07007295mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007296{
7297 u32 info = log_info & 0x00FF0000;
7298 char *desc = "unknown";
7299
7300 switch (info) {
7301 case 0x00010000:
7302 desc = "bug! MID not found";
7303 if (ioc->reload_fw == 0)
7304 ioc->reload_fw++;
7305 break;
7306
7307 case 0x00020000:
7308 desc = "Parity Error";
7309 break;
7310
7311 case 0x00030000:
7312 desc = "ASYNC Outbound Overrun";
7313 break;
7314
7315 case 0x00040000:
7316 desc = "SYNC Offset Error";
7317 break;
7318
7319 case 0x00050000:
7320 desc = "BM Change";
7321 break;
7322
7323 case 0x00060000:
7324 desc = "Msg In Overflow";
7325 break;
7326
7327 case 0x00070000:
7328 desc = "DMA Error";
7329 break;
7330
7331 case 0x00080000:
7332 desc = "Outbound DMA Overrun";
7333 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007334
Linus Torvalds1da177e2005-04-16 15:20:36 -07007335 case 0x00090000:
7336 desc = "Task Management";
7337 break;
7338
7339 case 0x000A0000:
7340 desc = "Device Problem";
7341 break;
7342
7343 case 0x000B0000:
7344 desc = "Invalid Phase Change";
7345 break;
7346
7347 case 0x000C0000:
7348 desc = "Untagged Table Size";
7349 break;
Christoph Hellwigc6678e02005-08-18 16:24:53 +02007350
Linus Torvalds1da177e2005-04-16 15:20:36 -07007351 }
7352
7353 printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
7354}
7355
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007356/* strings for sas loginfo */
7357 static char *originator_str[] = {
7358 "IOP", /* 00h */
7359 "PL", /* 01h */
7360 "IR" /* 02h */
7361 };
7362 static char *iop_code_str[] = {
7363 NULL, /* 00h */
7364 "Invalid SAS Address", /* 01h */
7365 NULL, /* 02h */
7366 "Invalid Page", /* 03h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007367 "Diag Message Error", /* 04h */
7368 "Task Terminated", /* 05h */
7369 "Enclosure Management", /* 06h */
7370 "Target Mode" /* 07h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007371 };
7372 static char *pl_code_str[] = {
7373 NULL, /* 00h */
7374 "Open Failure", /* 01h */
7375 "Invalid Scatter Gather List", /* 02h */
7376 "Wrong Relative Offset or Frame Length", /* 03h */
7377 "Frame Transfer Error", /* 04h */
7378 "Transmit Frame Connected Low", /* 05h */
7379 "SATA Non-NCQ RW Error Bit Set", /* 06h */
7380 "SATA Read Log Receive Data Error", /* 07h */
7381 "SATA NCQ Fail All Commands After Error", /* 08h */
7382 "SATA Error in Receive Set Device Bit FIS", /* 09h */
7383 "Receive Frame Invalid Message", /* 0Ah */
7384 "Receive Context Message Valid Error", /* 0Bh */
7385 "Receive Frame Current Frame Error", /* 0Ch */
7386 "SATA Link Down", /* 0Dh */
7387 "Discovery SATA Init W IOS", /* 0Eh */
7388 "Config Invalid Page", /* 0Fh */
7389 "Discovery SATA Init Timeout", /* 10h */
7390 "Reset", /* 11h */
7391 "Abort", /* 12h */
7392 "IO Not Yet Executed", /* 13h */
7393 "IO Executed", /* 14h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007394 "Persistent Reservation Out Not Affiliation "
7395 "Owner", /* 15h */
Moore, Eric5bf52c42006-03-14 09:14:01 -07007396 "Open Transmit DMA Abort", /* 16h */
Eric Moore4f766dc2006-07-11 17:24:07 -06007397 "IO Device Missing Delay Retry", /* 17h */
Eric Moorec6c727a2007-01-29 09:44:54 -07007398 "IO Cancelled Due to Recieve Error", /* 18h */
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007399 NULL, /* 19h */
7400 NULL, /* 1Ah */
7401 NULL, /* 1Bh */
7402 NULL, /* 1Ch */
7403 NULL, /* 1Dh */
7404 NULL, /* 1Eh */
7405 NULL, /* 1Fh */
7406 "Enclosure Management" /* 20h */
7407 };
Eric Moorec6c727a2007-01-29 09:44:54 -07007408 static char *ir_code_str[] = {
7409 "Raid Action Error", /* 00h */
7410 NULL, /* 00h */
7411 NULL, /* 01h */
7412 NULL, /* 02h */
7413 NULL, /* 03h */
7414 NULL, /* 04h */
7415 NULL, /* 05h */
7416 NULL, /* 06h */
7417 NULL /* 07h */
7418 };
7419 static char *raid_sub_code_str[] = {
7420 NULL, /* 00h */
7421 "Volume Creation Failed: Data Passed too "
7422 "Large", /* 01h */
7423 "Volume Creation Failed: Duplicate Volumes "
7424 "Attempted", /* 02h */
7425 "Volume Creation Failed: Max Number "
7426 "Supported Volumes Exceeded", /* 03h */
7427 "Volume Creation Failed: DMA Error", /* 04h */
7428 "Volume Creation Failed: Invalid Volume Type", /* 05h */
7429 "Volume Creation Failed: Error Reading "
7430 "MFG Page 4", /* 06h */
7431 "Volume Creation Failed: Creating Internal "
7432 "Structures", /* 07h */
7433 NULL, /* 08h */
7434 NULL, /* 09h */
7435 NULL, /* 0Ah */
7436 NULL, /* 0Bh */
7437 NULL, /* 0Ch */
7438 NULL, /* 0Dh */
7439 NULL, /* 0Eh */
7440 NULL, /* 0Fh */
7441 "Activation failed: Already Active Volume", /* 10h */
7442 "Activation failed: Unsupported Volume Type", /* 11h */
7443 "Activation failed: Too Many Active Volumes", /* 12h */
7444 "Activation failed: Volume ID in Use", /* 13h */
7445 "Activation failed: Reported Failure", /* 14h */
7446 "Activation failed: Importing a Volume", /* 15h */
7447 NULL, /* 16h */
7448 NULL, /* 17h */
7449 NULL, /* 18h */
7450 NULL, /* 19h */
7451 NULL, /* 1Ah */
7452 NULL, /* 1Bh */
7453 NULL, /* 1Ch */
7454 NULL, /* 1Dh */
7455 NULL, /* 1Eh */
7456 NULL, /* 1Fh */
7457 "Phys Disk failed: Too Many Phys Disks", /* 20h */
7458 "Phys Disk failed: Data Passed too Large", /* 21h */
7459 "Phys Disk failed: DMA Error", /* 22h */
7460 "Phys Disk failed: Invalid <channel:id>", /* 23h */
7461 "Phys Disk failed: Creating Phys Disk Config "
7462 "Page", /* 24h */
7463 NULL, /* 25h */
7464 NULL, /* 26h */
7465 NULL, /* 27h */
7466 NULL, /* 28h */
7467 NULL, /* 29h */
7468 NULL, /* 2Ah */
7469 NULL, /* 2Bh */
7470 NULL, /* 2Ch */
7471 NULL, /* 2Dh */
7472 NULL, /* 2Eh */
7473 NULL, /* 2Fh */
7474 "Compatibility Error: IR Disabled", /* 30h */
7475 "Compatibility Error: Inquiry Comand Failed", /* 31h */
7476 "Compatibility Error: Device not Direct Access "
7477 "Device ", /* 32h */
7478 "Compatibility Error: Removable Device Found", /* 33h */
7479 "Compatibility Error: Device SCSI Version not "
7480 "2 or Higher", /* 34h */
7481 "Compatibility Error: SATA Device, 48 BIT LBA "
7482 "not Supported", /* 35h */
7483 "Compatibility Error: Device doesn't have "
7484 "512 Byte Block Sizes", /* 36h */
7485 "Compatibility Error: Volume Type Check Failed", /* 37h */
7486 "Compatibility Error: Volume Type is "
7487 "Unsupported by FW", /* 38h */
7488 "Compatibility Error: Disk Drive too Small for "
7489 "use in Volume", /* 39h */
7490 "Compatibility Error: Phys Disk for Create "
7491 "Volume not Found", /* 3Ah */
7492 "Compatibility Error: Too Many or too Few "
7493 "Disks for Volume Type", /* 3Bh */
7494 "Compatibility Error: Disk stripe Sizes "
7495 "Must be 64KB", /* 3Ch */
7496 "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
7497 };
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007498
7499/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007500/**
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007501 * mpt_sas_log_info - Log information returned from SAS IOC.
7502 * @ioc: Pointer to MPT_ADAPTER structure
7503 * @log_info: U32 LogInfo reply word from the IOC
7504 *
7505 * Refer to lsi/mpi_log_sas.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007506 **/
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007507static void
7508mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
7509{
7510union loginfo_type {
7511 u32 loginfo;
7512 struct {
7513 u32 subcode:16;
7514 u32 code:8;
7515 u32 originator:4;
7516 u32 bus_type:4;
7517 }dw;
7518};
7519 union loginfo_type sas_loginfo;
Eric Moorec6c727a2007-01-29 09:44:54 -07007520 char *originator_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007521 char *code_desc = NULL;
Eric Moorec6c727a2007-01-29 09:44:54 -07007522 char *sub_code_desc = NULL;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007523
7524 sas_loginfo.loginfo = log_info;
7525 if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007526 (sas_loginfo.dw.originator < ARRAY_SIZE(originator_str)))
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007527 return;
Eric Moorec6c727a2007-01-29 09:44:54 -07007528
7529 originator_desc = originator_str[sas_loginfo.dw.originator];
7530
7531 switch (sas_loginfo.dw.originator) {
7532
7533 case 0: /* IOP */
7534 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007535 ARRAY_SIZE(iop_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007536 code_desc = iop_code_str[sas_loginfo.dw.code];
7537 break;
7538 case 1: /* PL */
7539 if (sas_loginfo.dw.code <
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007540 ARRAY_SIZE(pl_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007541 code_desc = pl_code_str[sas_loginfo.dw.code];
7542 break;
7543 case 2: /* IR */
7544 if (sas_loginfo.dw.code >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007545 ARRAY_SIZE(ir_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007546 break;
7547 code_desc = ir_code_str[sas_loginfo.dw.code];
7548 if (sas_loginfo.dw.subcode >=
Julia Lawalldd7c34e2008-11-09 17:55:27 +01007549 ARRAY_SIZE(raid_sub_code_str))
Eric Moorec6c727a2007-01-29 09:44:54 -07007550 break;
7551 if (sas_loginfo.dw.code == 0)
7552 sub_code_desc =
7553 raid_sub_code_str[sas_loginfo.dw.subcode];
7554 break;
7555 default:
7556 return;
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007557 }
7558
Eric Moorec6c727a2007-01-29 09:44:54 -07007559 if (sub_code_desc != NULL)
7560 printk(MYIOC_s_INFO_FMT
7561 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7562 " SubCode={%s}\n",
7563 ioc->name, log_info, originator_desc, code_desc,
7564 sub_code_desc);
7565 else if (code_desc != NULL)
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007566 printk(MYIOC_s_INFO_FMT
7567 "LogInfo(0x%08x): Originator={%s}, Code={%s},"
7568 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007569 ioc->name, log_info, originator_desc, code_desc,
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007570 sas_loginfo.dw.subcode);
7571 else
7572 printk(MYIOC_s_INFO_FMT
7573 "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
7574 " SubCode(0x%04x)\n",
Eric Moorec6c727a2007-01-29 09:44:54 -07007575 ioc->name, log_info, originator_desc,
7576 sas_loginfo.dw.code, sas_loginfo.dw.subcode);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06007577}
7578
Linus Torvalds1da177e2005-04-16 15:20:36 -07007579/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007580/**
Eric Moorec6c727a2007-01-29 09:44:54 -07007581 * mpt_iocstatus_info_config - IOCSTATUS information for config pages
7582 * @ioc: Pointer to MPT_ADAPTER structure
Randy Dunlap1544d672007-02-20 11:17:03 -08007583 * @ioc_status: U32 IOCStatus word from IOC
Eric Moorec6c727a2007-01-29 09:44:54 -07007584 * @mf: Pointer to MPT request frame
7585 *
7586 * Refer to lsi/mpi.h.
7587 **/
7588static void
7589mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
7590{
7591 Config_t *pReq = (Config_t *)mf;
7592 char extend_desc[EVENT_DESCR_STR_SZ];
7593 char *desc = NULL;
7594 u32 form;
7595 u8 page_type;
7596
7597 if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
7598 page_type = pReq->ExtPageType;
7599 else
7600 page_type = pReq->Header.PageType;
7601
7602 /*
7603 * ignore invalid page messages for GET_NEXT_HANDLE
7604 */
7605 form = le32_to_cpu(pReq->PageAddress);
7606 if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
7607 if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
7608 page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
7609 page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
7610 if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
7611 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
7612 return;
7613 }
7614 if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
7615 if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
7616 MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
7617 return;
7618 }
7619
7620 snprintf(extend_desc, EVENT_DESCR_STR_SZ,
7621 "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
7622 page_type, pReq->Header.PageNumber, pReq->Action, form);
7623
7624 switch (ioc_status) {
7625
7626 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7627 desc = "Config Page Invalid Action";
7628 break;
7629
7630 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7631 desc = "Config Page Invalid Type";
7632 break;
7633
7634 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7635 desc = "Config Page Invalid Page";
7636 break;
7637
7638 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7639 desc = "Config Page Invalid Data";
7640 break;
7641
7642 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7643 desc = "Config Page No Defaults";
7644 break;
7645
7646 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
7647 desc = "Config Page Can't Commit";
7648 break;
7649 }
7650
7651 if (!desc)
7652 return;
7653
Eric Moore29dd3602007-09-14 18:46:51 -06007654 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
7655 ioc->name, ioc_status, desc, extend_desc));
Eric Moorec6c727a2007-01-29 09:44:54 -07007656}
7657
7658/**
7659 * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
Linus Torvalds1da177e2005-04-16 15:20:36 -07007660 * @ioc: Pointer to MPT_ADAPTER structure
7661 * @ioc_status: U32 IOCStatus word from IOC
7662 * @mf: Pointer to MPT request frame
7663 *
7664 * Refer to lsi/mpi.h.
Eric Moorec6c727a2007-01-29 09:44:54 -07007665 **/
Linus Torvalds1da177e2005-04-16 15:20:36 -07007666static void
Eric Moorec6c727a2007-01-29 09:44:54 -07007667mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007668{
7669 u32 status = ioc_status & MPI_IOCSTATUS_MASK;
Eric Moore4f766dc2006-07-11 17:24:07 -06007670 char *desc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007671
7672 switch (status) {
Eric Moorec6c727a2007-01-29 09:44:54 -07007673
7674/****************************************************************************/
7675/* Common IOCStatus values for all replies */
7676/****************************************************************************/
7677
Linus Torvalds1da177e2005-04-16 15:20:36 -07007678 case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
7679 desc = "Invalid Function";
7680 break;
7681
7682 case MPI_IOCSTATUS_BUSY: /* 0x0002 */
7683 desc = "Busy";
7684 break;
7685
7686 case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */
7687 desc = "Invalid SGL";
7688 break;
7689
7690 case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */
7691 desc = "Internal Error";
7692 break;
7693
7694 case MPI_IOCSTATUS_RESERVED: /* 0x0005 */
7695 desc = "Reserved";
7696 break;
7697
7698 case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */
7699 desc = "Insufficient Resources";
7700 break;
7701
7702 case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */
7703 desc = "Invalid Field";
7704 break;
7705
7706 case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */
7707 desc = "Invalid State";
7708 break;
7709
Eric Moorec6c727a2007-01-29 09:44:54 -07007710/****************************************************************************/
7711/* Config IOCStatus values */
7712/****************************************************************************/
7713
Linus Torvalds1da177e2005-04-16 15:20:36 -07007714 case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
7715 case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
7716 case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
7717 case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
7718 case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
7719 case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007720 mpt_iocstatus_info_config(ioc, status, mf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007721 break;
7722
Eric Moorec6c727a2007-01-29 09:44:54 -07007723/****************************************************************************/
7724/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
7725/* */
7726/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
7727/* */
7728/****************************************************************************/
7729
Linus Torvalds1da177e2005-04-16 15:20:36 -07007730 case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007731 case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
Eric Moorec6c727a2007-01-29 09:44:54 -07007732 case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
7733 case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
7734 case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
7735 case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007736 case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007737 case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007738 case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007739 case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007740 case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007741 case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
Eric Moorec6c727a2007-01-29 09:44:54 -07007742 case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007743 break;
7744
Eric Moorec6c727a2007-01-29 09:44:54 -07007745/****************************************************************************/
7746/* SCSI Target values */
7747/****************************************************************************/
7748
7749 case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
7750 desc = "Target: Priority IO";
7751 break;
7752
7753 case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
7754 desc = "Target: Invalid Port";
7755 break;
7756
7757 case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
7758 desc = "Target Invalid IO Index:";
7759 break;
7760
7761 case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
7762 desc = "Target: Aborted";
7763 break;
7764
7765 case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
7766 desc = "Target: No Conn Retryable";
7767 break;
7768
7769 case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
7770 desc = "Target: No Connection";
7771 break;
7772
7773 case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
7774 desc = "Target: Transfer Count Mismatch";
7775 break;
7776
7777 case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
7778 desc = "Target: STS Data not Sent";
7779 break;
7780
7781 case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
7782 desc = "Target: Data Offset Error";
7783 break;
7784
7785 case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
7786 desc = "Target: Too Much Write Data";
7787 break;
7788
7789 case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
7790 desc = "Target: IU Too Short";
7791 break;
7792
7793 case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
7794 desc = "Target: ACK NAK Timeout";
7795 break;
7796
7797 case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
7798 desc = "Target: Nak Received";
7799 break;
7800
7801/****************************************************************************/
7802/* Fibre Channel Direct Access values */
7803/****************************************************************************/
7804
7805 case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
7806 desc = "FC: Aborted";
7807 break;
7808
7809 case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
7810 desc = "FC: RX ID Invalid";
7811 break;
7812
7813 case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
7814 desc = "FC: DID Invalid";
7815 break;
7816
7817 case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
7818 desc = "FC: Node Logged Out";
7819 break;
7820
7821 case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
7822 desc = "FC: Exchange Canceled";
7823 break;
7824
7825/****************************************************************************/
7826/* LAN values */
7827/****************************************************************************/
7828
7829 case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
7830 desc = "LAN: Device not Found";
7831 break;
7832
7833 case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
7834 desc = "LAN: Device Failure";
7835 break;
7836
7837 case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
7838 desc = "LAN: Transmit Error";
7839 break;
7840
7841 case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
7842 desc = "LAN: Transmit Aborted";
7843 break;
7844
7845 case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
7846 desc = "LAN: Receive Error";
7847 break;
7848
7849 case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
7850 desc = "LAN: Receive Aborted";
7851 break;
7852
7853 case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
7854 desc = "LAN: Partial Packet";
7855 break;
7856
7857 case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
7858 desc = "LAN: Canceled";
7859 break;
7860
7861/****************************************************************************/
7862/* Serial Attached SCSI values */
7863/****************************************************************************/
7864
7865 case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
7866 desc = "SAS: SMP Request Failed";
7867 break;
7868
7869 case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
7870 desc = "SAS: SMP Data Overrun";
Linus Torvalds1da177e2005-04-16 15:20:36 -07007871 break;
7872
7873 default:
7874 desc = "Others";
7875 break;
7876 }
Eric Moorec6c727a2007-01-29 09:44:54 -07007877
7878 if (!desc)
7879 return;
7880
Eric Moore29dd3602007-09-14 18:46:51 -06007881 dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
7882 ioc->name, status, desc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007883}
7884
7885/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007886EXPORT_SYMBOL(mpt_attach);
7887EXPORT_SYMBOL(mpt_detach);
7888#ifdef CONFIG_PM
7889EXPORT_SYMBOL(mpt_resume);
7890EXPORT_SYMBOL(mpt_suspend);
7891#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007892EXPORT_SYMBOL(ioc_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007893EXPORT_SYMBOL(mpt_register);
7894EXPORT_SYMBOL(mpt_deregister);
7895EXPORT_SYMBOL(mpt_event_register);
7896EXPORT_SYMBOL(mpt_event_deregister);
7897EXPORT_SYMBOL(mpt_reset_register);
7898EXPORT_SYMBOL(mpt_reset_deregister);
7899EXPORT_SYMBOL(mpt_device_driver_register);
7900EXPORT_SYMBOL(mpt_device_driver_deregister);
7901EXPORT_SYMBOL(mpt_get_msg_frame);
7902EXPORT_SYMBOL(mpt_put_msg_frame);
Prakash, Sathya7a195f42007-08-14 16:08:40 +05307903EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007904EXPORT_SYMBOL(mpt_free_msg_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007905EXPORT_SYMBOL(mpt_send_handshake_request);
7906EXPORT_SYMBOL(mpt_verify_adapter);
7907EXPORT_SYMBOL(mpt_GetIocState);
7908EXPORT_SYMBOL(mpt_print_ioc_summary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007909EXPORT_SYMBOL(mpt_HardResetHandler);
7910EXPORT_SYMBOL(mpt_config);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007911EXPORT_SYMBOL(mpt_findImVolumes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007912EXPORT_SYMBOL(mpt_alloc_fw_memory);
7913EXPORT_SYMBOL(mpt_free_fw_memory);
Christoph Hellwig82ffb6712005-09-09 16:25:54 +02007914EXPORT_SYMBOL(mptbase_sas_persist_operation);
Eric Mooreb506ade2007-01-29 09:45:37 -07007915EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007916
Linus Torvalds1da177e2005-04-16 15:20:36 -07007917/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007918/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007919 * fusion_init - Fusion MPT base driver initialization routine.
7920 *
7921 * Returns 0 for success, non-zero for failure.
7922 */
7923static int __init
7924fusion_init(void)
7925{
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307926 u8 cb_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007927
7928 show_mptmod_ver(my_NAME, my_VERSION);
7929 printk(KERN_INFO COPYRIGHT "\n");
7930
Prakash, Sathyaf606f572007-08-14 16:12:53 +05307931 for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
7932 MptCallbacks[cb_idx] = NULL;
7933 MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
7934 MptEvHandlers[cb_idx] = NULL;
7935 MptResetHandlers[cb_idx] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007936 }
7937
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007938 /* Register ourselves (mptbase) in order to facilitate
Linus Torvalds1da177e2005-04-16 15:20:36 -07007939 * EventNotification handling.
7940 */
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05307941 mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007942
7943 /* Register for hard reset handling callbacks.
7944 */
Prakash, Sathya436ace72007-07-24 15:42:08 +05307945 mpt_reset_register(mpt_base_index, mpt_ioc_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007946
7947#ifdef CONFIG_PROC_FS
7948 (void) procmpt_create();
7949#endif
Moore, Eric Dean 7fadc872005-04-22 18:01:16 -04007950 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007951}
7952
7953/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Randy Dunlapd9489fb2006-12-06 20:38:43 -08007954/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07007955 * fusion_exit - Perform driver unload cleanup.
7956 *
7957 * This routine frees all resources associated with each MPT adapter
7958 * and removes all %MPT_PROCFS_MPTBASEDIR entries.
7959 */
7960static void __exit
7961fusion_exit(void)
7962{
7963
Linus Torvalds1da177e2005-04-16 15:20:36 -07007964 mpt_reset_deregister(mpt_base_index);
7965
7966#ifdef CONFIG_PROC_FS
7967 procmpt_destroy();
7968#endif
7969}
7970
Linus Torvalds1da177e2005-04-16 15:20:36 -07007971module_init(fusion_init);
7972module_exit(fusion_exit);